phpunit 模拟方法具有不同参数的多个调用

2022-08-30 06:52:37

有没有办法为不同的输入参数定义不同的模拟期望?例如,我有一个名为DB的数据库层类。此类具有名为“Query( string $query )”的方法,该方法在输入时采用 SQL 查询字符串。是否可以为此类 (DB) 创建 mock,并为依赖于输入查询字符串的不同 Query 方法调用设置不同的返回值?


答案 1

如果您可以避免使用它,那么使用它并不理想,因为正如他们的文档所声称的那样at()

at() 匹配器的 $index 参数是指给定模拟对象的所有方法调用中从零开始的索引。使用此匹配器时要小心,因为它可能导致与特定实现细节密切相关的脆性测试。

从4.1开始,您可以使用例如。withConsecutive

$mock->expects($this->exactly(2))
     ->method('set')
     ->withConsecutive(
         [$this->equalTo('foo'), $this->greaterThan(0)],
         [$this->equalTo('bar'), $this->greaterThan(0)]
       );

如果要使其在连续调用时返回:

  $mock->method('set')
         ->withConsecutive([$argA1, $argA2], [$argB1], [$argC1, $argC2])
         ->willReturnOnConsecutiveCalls($retValueA, $retValueB, $retValueC);

答案 2

PHPUnit 模拟库(默认情况下)确定期望是否仅基于传递给参数的匹配器和传递给 的约束进行匹配。因此,两个仅在传递到的参数上不同的调用将失败,因为两个调用都将匹配,但只有一个将验证是否具有预期的行为。请参阅实际工作示例之后的复制案例。expectsmethodexpectwith


对于您的问题,您需要使用或->will($this->returnCallback(有关该主题的另一个问题所述。->at()

例:

<?php

class DB {
    public function Query($sSql) {
        return "";
    }
}

class fooTest extends PHPUnit_Framework_TestCase {


    public function testMock() {

        $mock = $this->getMock('DB', array('Query'));

        $mock
            ->expects($this->exactly(2))
            ->method('Query')
            ->with($this->logicalOr(
                 $this->equalTo('select * from roles'),
                 $this->equalTo('select * from users')
             ))
            ->will($this->returnCallback(array($this, 'myCallback')));

        var_dump($mock->Query("select * from users"));
        var_dump($mock->Query("select * from roles"));
    }

    public function myCallback($foo) {
        return "Called back: $foo";
    }
}

再现:

phpunit foo.php
PHPUnit 3.5.13 by Sebastian Bergmann.

string(32) "Called back: select * from users"
string(32) "Called back: select * from roles"
.

Time: 0 seconds, Memory: 4.25Mb

OK (1 test, 1 assertion)


重现为什么两个 ->with() 调用不起作用:

<?php

class DB {
    public function Query($sSql) {
        return "";
    }
}

class fooTest extends PHPUnit_Framework_TestCase {


    public function testMock() {

        $mock = $this->getMock('DB', array('Query'));
        $mock
            ->expects($this->once())
            ->method('Query')
            ->with($this->equalTo('select * from users'))
            ->will($this->returnValue(array('fred', 'wilma', 'barney')));

        $mock
            ->expects($this->once())
            ->method('Query')
            ->with($this->equalTo('select * from roles'))
            ->will($this->returnValue(array('admin', 'user')));

        var_dump($mock->Query("select * from users"));
        var_dump($mock->Query("select * from roles"));
    }

}

结果在

 phpunit foo.php
PHPUnit 3.5.13 by Sebastian Bergmann.

F

Time: 0 seconds, Memory: 4.25Mb

There was 1 failure:

1) fooTest::testMock
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-select * from roles
+select * from users

/home/.../foo.php:27

FAILURES!
Tests: 1, Assertions: 0, Failures: 1

推荐