检查是否在没有传递任何参数的情况下调用mock的方法(在phpunit中)

时间:2012-02-28 02:44:19

标签: php unit-testing testing phpunit

在phpunit中,我们可以指定使用特定的

调用方法
->with($this->equalTo('foobar'))

或任何

->with($this->anything())

参数。

但是有没有办法指定在没有参数的情况下调用该方法?

这是我期望失败的测试:

public function testZ()
{
    $a = $this->getMock('q');

    $a->expects($this->once())
        ->method('z')
        ->with(); // <--- what constraint to specify here?

    $a->z(1);
}

UPD

这个问题具有理论性质,所以我没有任何现实生活的例子。在某些情况下,我现在可以想到的是:

public function testMe($object)
{
    $object->foo();
}

让我们假设testMe应该(按设计和要求)总是调用没有参数的方法(假设foo()有默认值)。因为在这种情况下,任何非默认参数(更精确:任何参数!=默认参数,我们还不知道,哪些可能可以独立更改)会导致致命的后果。

2 个答案:

答案 0 :(得分:7)

虽然rdlowrey是正确的,with()没有规定检查没有传递参数,问题不在于PHPUnit而在于PHP本身。

首先,如果您的方法没有提供默认值,如果您没有传递任何参数,解释器将引发致命错误。这是预期的,与手头的问题并不完全相关,但重要的是要预先说明。

其次,如果您的方法 提供默认值,则调用不带参数的方法将导致PHP在PHPUnit涉及传递默认值之前更改调用。这是一个简单的测试,演示PHP在PHP检查参数之前插入自身。关键是要认识到PHP创建的模拟类与模拟类具有相同的签名 - 包括默认值。

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;
        }
}

这意味着您可以验证 没有传递任何内容或传递了默认值,但您无法更具体。

你能解决这个限制吗?您可以在重写方法时从参数中删除默认值,因此您应该能够创建子类并对其进行模拟。这值得么?我最初的直觉反应是,这是一个巨大的代码味道。您的设计或测试都是错误的(t​​m)。

如果你能提供一个真实的,具体的例子,你真的需要做这种测试,那么花一些时间思考一个解决方案是值得的。在那之前,我对“不要那样做”的纯粹学术回答感到满意。 :)

答案 1 :(得分:4)

PHPUnit模拟对象只能使用->with()约束方法来验证传递的参数的计数或相应值是否与调用时传递给模拟方法的值相匹配。您无法使用它来要求将无参数传递给模拟方法。

模拟验证过程专门检查传递的参数计数和关联值是否与传递给with约束的值兼容。此外,正如您可能已经看到的那样,指定with约束而没有任何值也不起作用;如果with没有收到参数,则不会为验证添加任何参数约束。

您可以看到用于验证链接github源中的模拟方法参数的实际PHPUnit_Framework_MockObject_Matcher_Parameters::verify方法。

如果要求验证没有传递的参数,则需要指定自己的模拟类来验证PHPUnit模拟功能之外的这种情况。