PHPUnit Mock修改预期结果

13

我有一个简单的使用场景。我想要一个setUp方法,让我的mock对象返回一个默认值:

$this->myservice
        ->expects($this->any())
        ->method('checkUniqueness')
        ->will($this->returnValue(true));

但在某些测试中,我希望返回一个不同的值:

$this->myservice
        ->expects($this->exactly(1))
        ->method('checkUniqueness')
        ->will($this->returnValue(false));

我过去使用过C++的GoogleMock,它有"returnByDefault"或类似的东西来处理这个问题。我无法确定PHPUnit是否支持此功能(没有API文档,且代码难以阅读以找到我需要的内容)。

现在我不能只是将$this->myservice更改为新的mock,因为在设置中,我将其传递给其他需要模拟或测试的对象。

我的另一个解决方案是放弃设置的好处,而是必须为每个测试构建所有的mocks。

3个回答

5

您可以将setUp()代码移动到另一个带参数的方法中。然后从setUp()调用此方法,您也可以从测试方法中调用它,但使用与默认值不同的参数。


1
这怎么能解决问题呢?setUp()方法无论如何都会被调用。 - Massimiliano Arione
1
@MassimilianoArione 是的,但是你可以重新创建 $this->myservice 并更改返回值。 - rndstr

1

setUp()中继续构建模拟,但在每个测试中单独设置期望:

class FooTest extends PHPUnit_Framework_TestCase {
  private $myservice;
  private $foo;
  public function setUp(){
    $this->myService = $this->getMockBuilder('myservice')->getMock();
    $this->foo = new Foo($this->myService);
  }


  public function testUniqueThing(){
     $this->myservice
        ->expects($this->any())
        ->method('checkUniqueness')
        ->will($this->returnValue(true));

     $this->assertEqual('baz', $this->foo->calculateTheThing());
  }

  public function testNonUniqueThing(){
     $this->myservice
        ->expects($this->any())
        ->method('checkUniqueness')
        ->will($this->returnValue(false));

     $this->assertEqual('bar', $this->foo->calculateTheThing());

  }


}

两个期望不会相互干扰,因为PHPUnit会实例化一个新的FooTest实例来运行每个测试。

0

另一个小技巧是通过引用传递变量。这样你就可以操纵它的值:

public function callApi(string $endpoint):bool
{
    // some logic ...
}

public function getCurlInfo():array 
{
    // returns curl info about the last request
}

上面的代码有两个公共方法:callApi()用于调用API,第二个getCurlInfo()方法提供了关于最后一次请求的信息。我们可以模拟getCurlInfo()的输出,根据传递的参数/模拟为callApi()传递变量作为引用:
$mockedHttpCode = 0;
$this->mockedApi
    ->method('callApi')
    ->will(
        // pass variable by reference:
        $this->returnCallback(function () use (&$mockedHttpCode) {
            $args = func_get_args();
            $maps = [
                ['endpoint/x', true, 200],
                ['endpoint/y', false, 404],
                ['endpoint/z', false, 403],
            ];
            foreach ($maps as $map) {
                if ($args == array_slice($map, 0, count($args))) {
                    // change variable:
                    $mockedHttpCode = $map[count($args) + 1];
                    return $map[count($args)];
                }
            }
            return [];
        })
    );

$this->mockedApi
    ->method('getCurlInfo')
    // pass variable by reference:
    ->willReturn(['http_code' => &$mockedHttpCode]);

仔细观察,returnCallback()逻辑实际上与returnValueMap()相同,只是在我们的情况下,我们可以添加第三个参数:服务器预期响应代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接