检查是否在不传递任何参数的情况下调用了模拟方法(在phpunit中) [英] Check that mock's method is called without any parameters passed (in phpunit)

查看:58
本文介绍了检查是否在不传递任何参数的情况下调用了模拟方法(在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()具有默认值).因为在这种情况下,任何非默认参数(更精确的说:任何参数!=都将成为默认值,我们尚不知道,并且可能会独立更改)会导致致命的后果.

解决方案

尽管rdlowrey正确地认为with()没有提供检查是否传递任何参数的规定,但问题不在于PHPUnit,而在于PHP本身. /p>

首先,如果您的方法未提供默认值,则如果您不传递任何参数,则解释器将引发致命错误.这是预料之中的,与当前的问题并不完全相关,但是预先声明很重要.

第二,如果您的方法提供,则在没有参数的情况下调用该方法将导致PHP在涉及PHPUnit传递默认值之前更改该调用.这是一个简单的测试,演示了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;
        }
}

这意味着您可以验证 没有传递任何内容或传递了默认值,但是您不能更具体地说明了.

您可以解决此限制吗?覆盖方法时,可以从参数中删除默认值,因此您应该能够创建一个子类并对其进行模拟.这值得么?我最初的直觉反应是,这是一种巨大的代码异味.您的设计或测试正在做错事(tm).

如果您可以提供一个实际的具体示例,实际需要进行这种测试,则值得花一些时间来思考解决方案.在那之前,我对不要那样做"这个纯粹的学术答案感到满意. :)

In phpunit we can specify the method was called with particular

->with($this->equalTo('foobar'))

or any

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

parameter.

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

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.

解决方案

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.

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.

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." :)

这篇关于检查是否在不传递任何参数的情况下调用了模拟方法(在phpunit中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆