【问题标题】:How can I test if same method is called with correct parameters with PHPUnit and mock object如何测试是否使用 PHPUnit 和模拟对象使用正确的参数调用相同的方法
【发布时间】:2010-11-21 15:23:23
【问题描述】:

我正在使用 PHPUnit 进行单元测试 我正在使用模拟对象来测试是否使用正确的参数调用方法。当我只想这样做一次时,这很好用。

    $logMock = $this->getMockBuilder('Logger')
            ->disableOriginalConstructor()
            ->getMock();

    //check if it updates the correct record
    $logMock->expects($this->exactly(1))
            ->method('updateLog')
            ->with(456, 'some status');

现在我想测试是否第二次调用 updateLog(使用不同的参数)。我不知道如何使用 'with' 方法来做到这一点。

有人有建议吗?

【问题讨论】:

    标签: php phpunit


    【解决方案1】:

    我不知道你的模拟框架。通常你只是创造另一个期望。我认为这也应该适用于这个框架。

    $logMock->expects($this->exactly(1))
             ->method('updateLog')
             ->with(100, 'something else');
    

    编辑

    PHPUnit 框架似乎不支持对同一方法的多个不同期望。根据这个site,你必须使用索引功能。

    它看起来像这样

    $logMock->expects($this->at(0))
            ->method('updateLog')
            ->with(456, 'some status');
    $logMock->expects($this->at(1))
             ->method('updateLog')
             ->with(100, 'something else');
    $logMock->expects($this->exactly(2))
            ->method('updateLog');
    

    【讨论】:

    • 我正在使用 PHPUnit 内部模拟功能。在我的实现(正在测试的方法)中,updateLog 被调用了两次,所以我无法测试具有不同期望的方法参数。
    • 根据这个站点,您可以通过使用调用索引功能来实现这一点。 kreamer.org/phpunit-cookbook/1.0/mocks/…
    • 谢谢! $this->at(index) 完成了这项工作。也感谢网站的链接,一些有用的信息。
    • 遗憾的是,使用索引并不是最好的解决方案。如果您只是在方法中重新排序代码而不更改实际功能,您的测试将会中断。但是在今天的PHPUnit中确实没有很好的解决方案,所以不得不这样做。
    • 是的,这是真的,这是一个很好的观点。我不使用 PHPUnit,我在 .net 和 java 部分工作得更多。并且在那里(例如最小起订量)您可以为每个方法添加多个期望,而无需指定严格的顺序。
    【解决方案2】:

    returnCallback

    如果您不能使用withConsecutive(),可能是因为您使用的是旧版本的PHPUnit,您可以选择returnCallback。

    每次调用模拟方法时都会调用returnCallback 函数。这意味着您可以保存传递给它的参数以供以后检查。例如:

    $actualArgs = array();
    
    $mockDependency->expects($this->any())
        ->method('setOption')
        ->will($this->returnCallback(
            function($option, $value) use (&$actualArgs){
                $actualArgs[] = array($option, $value);
            }
        ));
    
    $serviceUnderTest->executeMethodUnderTest();
    
    $this->assertEquals(
        array(
            array('first arg of first call', 'second arg of first call'),
            array('first arg of second call', 'second arg of second call'),
        ),
        $actualArgs);
    

    【讨论】:

    • 这确实为我节省了数小时的谷歌搜索时间。谢谢。
    【解决方案3】:

    从 PHPUnit 4.2 开始,您可以使用 withConsecutive 断言。前提是您知道调用的顺序。你的模拟应该是这样的:

    $logMock->expects($this->exactly(2))
            ->method('updateLog')
            ->withConsecutive(
                array(456, 'some status')
                array(100, 'something else')
            );
    

    【讨论】:

      【解决方案4】:

      前面的答案是正确的。

      您可以在 PHPUnit 手册中找到答案 http://www.phpunit.de/manual/3.6/en/phpunit-book.html#test-doubles.mock-objects.tables.matchers 搜索匹配器。 匹配器是由 any()、never() 等函数返回的类... 您需要的是 PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex,由 at() 方法返回

      您可以通过浏览 PHPUnit 类找到更多信息(添加到项目路径并使用类似 netbeans 的 IDE 跳转到它们,看看您可以使用什么)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-13
        • 2017-02-27
        • 2018-03-10
        • 2019-01-27
        • 2023-03-12
        • 2022-08-22
        • 1970-01-01
        • 2018-05-28
        相关资源
        最近更新 更多