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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (15)

对于不同的输入参数,是否有任何方法来定义不同的模拟期望?例如,我有一个名为DB的数据库层类。这个类有一个叫做“query(String$Query)”的方法,该方法在输入时接受一个SQL查询字符串。我是否可以为这个类(DB)创建模拟,并为依赖于输入查询字符串的不同查询方法调用设置不同的返回值?

提问于
用户回答回答于

PHPUnit模拟库(默认情况下)仅根据传递给expects参数和传递给method因为这个,两个expect只在传递给with将失败,因为两者都匹配,但只有一个将验证是否具有预期的行为。请参阅实际工作示例之后的再现案例。

对于你需要使用的问题->at()->will($this->returnCallback

例子:

<?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)

重现为什么2->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
用户回答回答于

使用起来不太理想at()如果你能避免因为

at()matcher的$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);

扫码关注云+社区