在 PHPUnit 中,如何在连续调用模拟方法时指示不同的 with() ?

问题描述 投票:0回答:4

我想使用不同的预期参数调用我的模拟方法两次。这不起作用,因为

expects($this->once())
将在第二次调用时失败。

$mock->expects($this->once())
     ->method('foo')
     ->with('someValue');

$mock->expects($this->once())
     ->method('foo')
     ->with('anotherValue');

$mock->foo('someValue');
$mock->foo('anotherValue');

我也尝试过:

$mock->expects($this->exactly(2))
     ->method('foo')
     ->with('someValue');

但是如何添加 with() 来匹配第二个调用?

php mocking phpunit
4个回答
70
投票

您需要使用

at()

$mock->expects($this->at(0))
     ->method('foo')
     ->with('someValue');

$mock->expects($this->at(1))
     ->method('foo')
     ->with('anotherValue');

$mock->foo('someValue');
$mock->foo('anotherValue');

请注意,传递给

at()
的索引适用于对同一模拟对象的所有方法调用。如果第二个方法调用是
bar()
,您不会将参数更改为
at()


32
投票

参考来自类似问题的答案

从 PHPUnit 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);

如果可以避免的话,使用

at()
并不理想,因为 正如他们的文档声称的那样

at() 匹配器的 $index 参数指的是给定模拟对象的所有方法调用中从零开始的索引。使用此匹配器时请务必小心,因为它可能会导致与特定实现细节联系过于紧密的脆弱测试。


3
投票

withConsecutive
也已弃用。
这个帖子里有一个解决方案: 替换 PHPUnit 方法 `withConsecutive`


0
投票

as ->at() 和 withConsecutive() 已弃用 我是这样解决的:

如果我们有:

$this->service->foo(
    fooFirstParameter: 'firstParamForTheFirstCall',
    fooSecondParameter: 'secondParamForTheFirstCall'
);

$this->service->foo(
    fooFirstParameter: 'firstParamForTheSecondCall',
    fooSecondParameter: 'secondParamForTheSecondCall'
);

然后我们可以模拟并期望参数和返回,如下所示:

$withFirstParameter = ['firstParamForTheFirstCall', 'firstParamForTheSecondCall'];
$withSeoncdParameter = ['secondParamForTheFirstCall', 'secondParamForTheSecondCall'];
$willReturn = ['willReturnInTheFirstCall', 'willReturnInTheSecondCall'];
$mock->expects($this->exactly(2))
     ->method('foo')
     ->willReturnCallback(
         function (
             $fooFirstParameter,
             $fooSecondParameter,
         ) use (
             &$withFirstParameter,
             &$withSeoncdParameter
             &$willReturn,
         ): string|null {
             $this->assertEquals(array_shift($withFirstParameter), $fooFirstParameter);
             $this->assertEquals(array_shift($withSeoncdParameter), $fooSecondParameter);
             return array_shift($willReturn);
         }
    );
© www.soinside.com 2019 - 2024. All rights reserved.