PHPUnit模拟库(默认情况下)仅根据传递给expects参数的匹配器和传递给method的约束来确定期望值是否匹配。仅在传递给with的自变量方面不同的两个expect调用将失败,因为两者将匹配但只有一个将验证为具有预期行为。见实际工作示例后的再现情况。 对于您的问题,您需要使用->at()或**->will($this->returnCallback(**,如another question on the subject中所述。
示例:
<?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
class SomeClass {
public function doSomething() {}
}
class StubTest extends \PHPUnit_Framework_TestCase {
public function testReturnValueMapStub() {
$mock = $this->getMock('SomeClass');
// Create a map of arguments to return values.
$map = array(
array('a', 'b', 'd'),
array('e', 'f', 'h')
);
// Configure the mock.
$mock->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));
// $mock->doSomething() returns different values depending on
// the provided arguments.
$this->assertEquals('d', $stub->doSomething('a', 'b'));
$this->assertEquals('h', $stub->doSomething('e', 'f'));
}
}
6条答案
按热度按时间xam8gpfp1#
如果可以避免使用
at()
,则使用它并不理想,因为as their docs claimat()匹配器的$index参数引用了一个给定的模拟对象的所有方法调用中的索引,从零开始。使用这个匹配器时要小心,因为它可能导致脆弱的测试,这些测试与特定的实现细节联系得太紧密了。
从4.1开始,您可以使用
withConsecutive
,例如。如果您想让它在连续呼叫时返回:
PHPUnit 10删除了
withConsecutive
。您可以通过以下方式获得类似的功能:很明显,它更丑,也不太一样,但这就是现状。你可以在这里读到更多关于替代品的信息:https://github.com/sebastianbergmann/phpunit/issues/4026和此处:https://github.com/sebastianbergmann/phpunit/issues/4026#issuecomment-825453794
wwodge7n2#
PHPUnit模拟库(默认情况下)仅根据传递给
expects
参数的匹配器和传递给method
的约束来确定期望值是否匹配。仅在传递给with
的自变量方面不同的两个expect
调用将失败,因为两者将匹配但只有一个将验证为具有预期行为。见实际工作示例后的再现情况。对于您的问题,您需要使用
->at()
或**->will($this->returnCallback(
**,如another question on the subject
中所述。示例:
重现:
重现两个-〉with()调用不起作用的原因:
结果
du7egjpx3#
根据我的发现,解决这个问题的最佳方法是使用PHPUnit的值Map功能。
PHPUnit文档中的示例:
此测试通过。如您所见:
据我所知,这个特性是在PHPUnit 3.6中引入的,所以它已经足够“古老”了,几乎可以在任何开发或过渡环境中安全地使用,也可以与任何持续集成工具一起使用。
qxsslcnc4#
看起来Mockery(https://github.com/padraic/mockery)支持这一点。在我的例子中,我想检查在数据库上创建了2个索引:
嘲笑,作品:
PHPUnit,这将失败:
Mockery也有一个更好的语法IMHO。它似乎比PHPUnits内置的模拟功能慢一点,但是YMMV。
p5cysglq5#
我们正在尝试在PHP8.1上用Phpunit 10升级测试,作为我们映像/库的年度升级。
在Phpunit 10上,at()和withConsecutive()已弃用。
@Radu Murzea的解决方案在大多数情况下有效:不是我们的!
我需要模拟MongoDB调用:参数有时是MongoDB\ObjectId;returnValueMap()使用===比较接收到的参数:如果对象比较失败,php文档显示php.net/manual/en/language.oop5.object-comparison.php
我模拟MongoDB FindOne的解决方案如下:
a2mppw5e6#
简介
好的,我看到有一个解决方案提供了嘲笑,所以我不喜欢嘲笑,我会给你一个预言替代品,但我会建议你首先read about the difference between Mockery and Prophecy first.
要涵盖的实际问题代码
PhpUnit预言解决方案
总结
我的技巧是利用Prophecy的消息绑定特性,尽管它看起来像一个典型的回调javascript代码,以**$self = $this开头;* * 因为你很少需要编写这样的单元测试,我认为这是一个很好的解决方案,而且它肯定很容易遵循,调试,因为它实际上描述了程序的执行。
顺便说一句:还有第二种选择,但需要修改我们正在测试的代码。我们可以 Package 麻烦制造者,并将他们移到一个单独的类中:
可以 Package 为:
就这样了,但我不想为它创建另一个类,我更喜欢第一个类.