12

我有一个简单的用例。我想要一个 setUp 方法,它会导致我的模拟对象返回一个默认值:

$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为一个新的模拟,因为在设置中,我将它传递给其他需要模拟或测试的东西。

我唯一的其他解决方案是我失去了设置的好处,而是必须为每次测试建立所有的模拟。

4

3 回答 3

3

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

于 2013-01-09T13:52:32.027 回答
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 实例来运行每个测试。

于 2017-06-02T19:41:58.417 回答
0

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

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

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

上面的代码有 2 个公共方法: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()-logic 实际上和 做同样的事情returnValueMap(),只是在我们的例子中,我们可以添加第三个参数:来自服务器的预期响应代码。

于 2018-09-05T11:36:47.123 回答