检查是否在没有传递任何参数的情况下调用了 mock 的方法(在 phpunit 中)
在 phpunit 中我们可以指定具体调用的方法
In phpunit we can specify the method was called with particular
->with($this->equalTo('foobar'))
或任何
->with($this->anything())
参数.
但是有没有办法指定该方法是在没有参数的情况下调用的?
But is there a way to specify that the method has been called without parameters at all?
这是我预计会失败的测试:
This is the test I expect to fail:
public function testZ()
{
$a = $this->getMock('q');
$a->expects($this->once())
->method('z')
->with(); // <--- what constraint to specify here?
$a->z(1);
}
UPD:
这个问题具有理论性质,所以我没有任何现实生活中的例子.我现在能想到的一些可能有用的情况是:
The question has theoretical nature, so I have no any real life example. Some case it could be useful I can think of right now is:
public function testMe($object)
{
$object->foo();
}
让我们假设 testMe
应该(根据设计和要求)始终调用不带参数的方法(假设 foo()
具有默认参数).因为在这种情况下,任何非默认参数(更准确地说:任何参数 != 到默认参数,我们还不知道并且可能会独立更改)都会导致致命的后果.
And let's assume that testMe
should (by design and by requirements) always call the method without parameters (assuming foo()
has default ones). Because any non-default parameter (more precise: any parameter != to default one, which we don't know yet and which probably could change independently) in this case causes fatal consequences.
推荐答案
虽然 rdlowrey 是正确的,with()
没有规定检查没有传递的参数,但问题不在于使用 PHPUnit,但使用 PHP 本身.
While rdlowrey is correct that with()
doesn't make provisions for checking for no arguments passed, the problem doesn't lie with PHPUnit but PHP itself.
首先,如果您的方法不提供默认值,如果您不传递任何参数,解释器将引发致命错误.这是意料之中的,与手头的问题并不完全相关,但提前说明这一点很重要.
First, if your method doesn't provide default values, the interpreter will raise a fatal error if you don't pass any parameters. This is expected and not entirely relevant to the question at hand, but it's important to state up front.
其次,如果您的方法确实提供了默认值,那么在不带参数的情况下调用该方法将导致 PHP 在 PHPUnit 参与传递默认值之前更改调用.这是一个简单的测试,演示 PHP 在 PHP 可以检查参数之前插入自身.认识到 PHP 创建的模拟类与模拟类具有相同的签名(包括默认值)是关键.
Second, if your method does provide default values, calling the method without arguments will cause PHP to alter the call before PHPUnit gets involved to pass the defaults instead. Here's a simple test that demonstrates PHP inserting itself before PHP can check the parameters. It's key to realize that the mock class that PHP creates has the same signature as the mocked class--including the defaults.
class MockTest extends PHPUnit_Framework_TestCase {
public function test() {
$mock = $this->getMock('Foo', array('bar'));
$mock->expects($this->once())
->method('bar')
->with() // does nothing, but it doesn't matter
->will($this->returnArgument(0));
self::assertEquals('foobar', $mock->bar()); // PHP inserts 1 and 2
// assertion fails because 1 != 'foobar'
}
}
class Foo {
public function bar($x = 1, $y = 2) {
return $x + $y;
}
}
这意味着您可以验证要么没有传递任何内容或传递了默认值,但你不能更具体.
This means you can verify that either nothing was passed or the default values were passed, but you cannot be more specific.
你能绕过这个限制吗?您可以在覆盖方法时从参数中删除默认值,因此您应该能够创建一个子类并模拟它.这值得么?我最初的直觉反应是,这是一种巨大的代码气味.您的设计或测试都在做错事(tm).
Can you get around this limitation? You can remove default values from arguments when overriding methods, so you should be able to create a subclass and mock it. Is it worth it? My initial gut reaction is that this is a huge code smell. Either your design or your tests are doing the Wrong Thing(tm).
如果您可以提供一个实际需要进行此类测试的真实的具体示例,那么值得花一些时间思考解决方案.在那之前,我对不要那样做"的纯学术回答感到满意.:)
If you can provide a real-world, concrete example where you actually need to do this kind of test, it's worth spending some time pondering a solution. Until then, I'm satisfied with the purely academic answer of "don't do that." :)
相关文章