在控制器中对模拟对象使用期望的最佳实践是啥

Posted

技术标签:

【中文标题】在控制器中对模拟对象使用期望的最佳实践是啥【英文标题】:What is the best practice to use expectations on mocked objects in controllers在控制器中对模拟对象使用期望的最佳实践是什么 【发布时间】:2021-02-28 12:56:03 【问题描述】:

我经常想在控制器中模拟出一个组件或对象。我使用 controllerSpy 方法来做到这一点:

public function controllerSpy($event, $controller = null)

    parent::controllerSpy($event, $controller);

    $OrderConfirmation = $this->getMockBuilder('OrderConfirmation')
        ->setMethods(['send'])
        ->getMock();
    $OrderConfirmation->expects($this->once())->method('send');
    $this->_controller->OrderConfirmation = $OrderConfirmation;

问题是在每个测试中都设置了调用 send-Method 的期望。但这取决于场景,存在不发送确认的场景。我想在测试本身中配置期望,而不是在 controllerSpy 方法中全局配置。像这样的:

public function testAddOrder()

    $this->_controller->OrderConfirmation->expects($this->once())->method('send');
    $this->post('/add_order');

但她的问题是期望会丢失,因为整个 OrderConfirmation 对象稍后会被覆盖。以前有人解决过这个问题吗?

【问题讨论】:

【参考方案1】:

您可以只听Controller.initialize 事件,这也是测试调度程序所做的:

public function testAddOrder()

    \Cake\Event\EventManager::instance()->on(
        'Controller.initialize',
        function (\Cake\Event\EventInterface $event) 
            /** @var \Cake\Controller\Controller $controller */
            $controller = $event->getSubject();
            
            // ...

            $controller->OrderConfirmation = $OrderConfirmation;
        
    );

    $this->post('/add_order');

或者为 controllerSpy() 方法实现一个回调,例如:

protected $controllerSpyCallback;

public function controllerSpy($event, $controller = null)

    parent::controllerSpy($event, $controller);

    if (is_callable($this->controllerSpyCallback)) 
        $this->controllerSpyCallback($this->_controller);
    


public function testAddOrder()

    $this->controllerSpyCallback = function (\Cake\Controller\Controller $controller) 
        // ...
        
        $controller->OrderConfirmation = $OrderConfirmation;
    ;

    $this->post('/add_order');

【讨论】:

以上是关于在控制器中对模拟对象使用期望的最佳实践是啥的主要内容,如果未能解决你的问题,请参考以下文章

使用 Selenium WebDriver 模拟 ENTER 或 RETURN 的最佳实践是啥

在 Verilog 模拟器和 VPI 代码中使用 make 的最佳实践是啥

IOS SDK - xcode interface builder - 管理许多对象的最佳实践是啥?

DAO(数据访问对象)最佳实践 - 我看到的示例同时使用 DAO 和服务对象,这里的最佳实践是啥?

RxSwift:使用 DisposeBag 的最佳实践是啥?

使用 Core Data 在视图中引用模型对象的最佳实践是啥?