dragon202076 2012-01-04 04:53
浏览 39
已采纳

使用PHPUnit模拟未在测试类中指定的以编程方式确定的方法

Using PHPUnit 3.6 I'm trying to test the exec() method in the below controller class. This method does two things:

  1. Determines the name of the method to call based on the object's existing properties, and ...
  2. If the determined controller method is callable it is executed and if not the method throws an exception

The (simplified) source code looks like this:

abstract class CLIController extends Controller
{
  /* irrelevant class details here */

  public function exec()
  {
    $action = ! empty($this->opts->args[0])
      ? $this->opts->args[0]
      : $this->default_action;

    if ( ! $action || ! is_callable(array($this, $action))) {
      $msg = 'Invalid controller action specified';
      throw new LogicException($msg);
    } else {
      $this->$action(); // <---- trying to get code coverage on this line!
    }
  }
}

So my problem is ...

I can't figure out how to get coverage on this part of the code:

} else {
  $this->$action();
}

because I'm not sure how to (or that it's even possible to) test the invocation of a method whose name is not known in the context of the abstract class. Again: the method to be called is declared in child classes. Normally I would just mock an abstract method but I can't in this case because the method doesn't exist yet -- it will be specified by a child class.

What might be the answer ...

  • ??? It may be possible that this line doesn't even need to be covered because it essentially relies on PHP's ability to correctly invoke a callable class method. If I successfully test that exec() throws an exception when it's supposed to, I know that correct functioning of the line in question depends on PHP functioning correctly. Does this invalidate the need to test it in the first place ???
  • If there is some way to mock the abstract class and create a method with a known name to add to the mocked class this would solve my problem and is what I've been trying unsuccessfully to do so far.
  • I know I could create a child class with a known method name but I don't believe it's a good idea to create a concrete child class just to test an abstract parent.
  • It could be that I need to refactor. One thing I don't want to do is leave child classes to implement the exec() function on their own.

What I've tried ...

  • Use some of PHP's reflection capabilities to no avail -- this may perhaps be due to my own inexperience with reflection and not its inability to handle this case, though.
  • Going back and forth through the PHPUnit manual and API docs. Unfortunately, as awesome as PHPUnit is, I often find the API documentation a bit light.

I would really appreciate any guidance on how best to proceed here. Thanks in advance.

  • 写回答

1条回答 默认 最新

  • dszm02606009 2012-01-04 07:32
    关注

    I disagree with your stipulation that "it's [not] a good idea to create a concrete child class just to test an abstract parent." I do this quite often when testing abstract classes and usually name the concrete subclass after the test to make it clear.

    class CLIControllerTest extends PHPUnit_Framework_TestCase
    {
        public function testCallsActionMethod()
        {
            $controller = new CLIControllerTest_WithActionMethod(...);
            // set $controller->opts->args[0] to 'action'
            $controller->exec();
            self::assertTrue($controller->called, 'Action method was called');
        }
    }
    
    class CLIControllerTest_WithActionMethod extends CLIController
    {
        public $called = false;
    
        public function action() {
            $this->called = true;
        }
    }
    

    The code to make this test happen is trivial and can be easily verified by inspection.

    I'm curious, why use is_callable instead of method_exists to avoid creating the array? It's probably just personal preference, but I'm wondering if there are any semantic differences.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 phython如何实现以下功能?查找同一用户名的消费金额合并—
  • ¥15 孟德尔随机化怎样画共定位分析图
  • ¥18 模拟电路问题解答有偿速度
  • ¥15 CST仿真别人的模型结果仿真结果S参数完全不对
  • ¥15 误删注册表文件致win10无法开启
  • ¥15 请问在阿里云服务器中怎么利用数据库制作网站
  • ¥60 ESP32怎么烧录自启动程序
  • ¥50 html2canvas超出滚动条不显示
  • ¥15 java业务性能问题求解(sql,业务设计相关)
  • ¥15 52810 尾椎c三个a 写蓝牙地址