【问题标题】:Mocking a method on dynamically allocated instance?在动态分配的实例上模拟方法?
【发布时间】:2014-11-04 04:47:16
【问题描述】:

背景:我正在开发一个 MVC 框架以进行一些实践,并希望确保所有内容都经过 100% 单元测试。

当前的设置是拥有一个应用程序类的实例 (Ex_App)。主脚本向 Dispatcher/Router 询问控制器名称。此控制器名称是实现Ex_Controller 的类的名称。结果作为Ex_Dispatch_Result 的实例返回。使用invokeController($dispatchResult) 函数将此结果传递给Ex_App 实例。

这就是魔法发生的地方。下面的清单是摘录:

$controllerName = $dispatchResult->getControllerName();
... checks for validaty of class name ...
$controller = new $controllerName();
$controller->prepare($this);

我正在使用 PHPUnit 进行单元测试,并且能够模拟调度结果,正确检查验证控制器的类名是否有效。问题是如何检查是否调用了prepare。

我想做类似的事情:

$mockController = $this->getMockBuilder('Ex_Controller')
  ->setMockClassName('Invoke_Correct_Controller')
  ->getMock();
$mockController->expects($this->once())->method('prepare');

但是,由于在调用 invokeController 时会创建一个新的 Invoke_Correct_Controller 实例,因此它不会是这个模拟对象,因此 expects() 调用是完全不相关的。

我可以让Ex_Dispatch_Result 类负责返回一个控制器并对其进行测试,但是在返回一个实例之前,我需要验证类名的正确性,并且我认为应该由Ex_App 类负责而不是“哑壳”Ex_Dispatch_Result 类。

我在 PHPUnit 框架中是否缺少一些我可以用来测试代码的东西,或者一些可以在我的实例中工作的有用模式?我觉得传递控制器名称比从一开始就传递控制器实例要好得多,因为它需要初始化每个可能的控制器。所以,我有点想坚持传递名称并使用 Ex_App 作为控制器实例的工厂。

也许我只是在考虑这个问题的一部分,但有时会发生这种情况。这就是为什么第三方的新外观经常起作用的原因:-)

【问题讨论】:

    标签: php unit-testing mocking phpunit


    【解决方案1】:

    你可以做几件事:

    • 提取控制器创建逻辑到单独的类,例如ControllerFactory,然后模拟控制器工厂实例,使其返回您的 $mockController。
    • 提取控制器创建逻辑以分离方法并使用部分模拟。
    • 从 $dispatchResult->getControllerName() 返回 $mockController,这可能需要模拟 $dispatchResult 甚至其他东西。

    如果您需要更详细的答案,请提供更多您的类和方法的代码示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-02
      • 2011-06-29
      • 2014-05-06
      • 1970-01-01
      • 1970-01-01
      • 2020-04-30
      • 1970-01-01
      相关资源
      最近更新 更多