【问题标题】:CakePHP3: Mock methods in integration tests?CakePHP3:集成测试中的模拟方法?
【发布时间】:2018-10-02 21:07:48
【问题描述】:

我是单元/集成测试的新手,我想对我的控制器进行集成测试,看起来像这样简化:

// ItemsController.php
public function edit() {

    // some edited item
    $itemEntity

    // some keywords
    $keywordEntities = [keyword1, keyword2, ...]

    // save item entity
    if (!$this->Items->save($itemEntity)) {
        // do some error handling
    }

    // add/replace item's keywords 
    if (!$this->Items->Keywords->replaceLinks($itemEntity, $keywordEntities)) {
       // do some error handling
    }
}

我有模型 ItemsKeywords 其中 Items 属于ToMany 关键字。我想测试控制器的错误处理部分。所以我必须模拟 save()replaceLinks() 方法,它们将返回 false。

我的集成测试如下所示:

// ItemsControllerTest.php
public function testEdit() {

    // mock save method
    $model = $this->getMockForModel('Items', ['save']);
    $model->expects($this->any())->method('save')->will($this->returnValue(false));

    // call the edit method of the controller and do some assertions...

}

这适用于 save() 方法。但它不适用于 replaceLinks() 方法。显然是因为它不是模型的一部分。

我也试过这样的:

$method = $this->getMockBuilder(BelongsToMany::class)
    ->setConstructorArgs([
        'Keywords', [
            'foreignKey' => 'item_id',
            'targetForeignKey' => 'keyword_id',
            'joinTable' => 'items_keywords'
        ]
    ])
    ->setMethods(['replaceLinks'])
    ->getMock();

$method->expects($this->any())->method('replaceLinks')->will($this->returnValue(false));

但这也行不通。模拟 replaceLinks() 方法的任何提示?

【问题讨论】:

    标签: testing cakephp cakephp-3.0


    【解决方案1】:

    在进行控制器测试时,我通常会尽量减少模拟,如果我想测试控制器中的错误处理,我会尝试触发实际错误,例如通过提供不符合应用程序/验证规则的数据。如果这是一个可行的选择,那么您可能想尝试一下。

    话虽如此,模拟关联的方法应该按照您的示例中所示的方式工作,但是您还需要用模拟替换实际的关联对象,因为与模型不同,关联没有全局注册表,其中可以放置模拟(这就是 getMockForModel() 将为您做的),以便您的应用程序代码无需进一步干预即可使用它们。

    应该这样做:

    $KeywordsAssociationMock = $this
        ->getMockBuilder(BelongsToMany::class) /* ... */;
    
    $associations = $this
        ->getTableLocator()
        ->get('Items')
        ->associations();
    
    $associations->add('Keywords', $KeywordsAssociationMock);
    

    这将修改表注册表中的Items 表对象,并将其实际Keywords 关联替换为模拟对象(关联集合的add() 更像一个setter,即覆盖)。如果你将它与模拟 Items 一起使用,那么你必须确保事先创建了 Items 模拟,否则在上面的示例中检索到的表将不是模拟的!

    【讨论】:

    • 感谢您的提示。您的解决方案无法开箱即用。我猜问题是模拟关联对象的正确构建,因为原始对象中有很多子对象。无论如何...我现在只是模拟了关键字模型的 save() 方法,因此 replaceLinks() 方法将失败,我可以测试我的错误处理。这工作正常。
    猜你喜欢
    • 1970-01-01
    • 2012-04-25
    • 2015-02-05
    • 2016-04-13
    • 1970-01-01
    • 2022-08-11
    • 2023-03-31
    • 2016-07-20
    • 2018-03-18
    相关资源
    最近更新 更多