php - 如何断言模拟对象的函数调用的对象参数

标签 php phpunit

考虑

class Foo {
    public $att;
    public function __construct ( $a ) { $this->att = $a; }
}

class Some {
    public function callMe ( Foo $f ) {}
}

// class I want to test
class SuT {
    public function testMe ( Some $s ) {
        echo $s->callMe( new Foo('hi') );
    }
}

我想检查 Sut::testMe() 是否正确调用了 Some::callMe()。由于参数是 (Foo) 对象(不是标量类型),我不知道如何调用 PHPUnit 的 with() 对其运行断言。例如,有一个 assertAttributeEquals 方法,但我如何向它提供调用的参数?

我想做的是:

class SuTTest extends PHPUnit_Framework_TestCase {
    public function testSuT () {
        $stub = $this->getMock( 'Some' );
        $stub->expects( $this->once() )->method( 'callMe' )
            ->with( $this->assertAttributeEquals('hi', 'att', $this->argument(0) );

        /*
         * Will $stub->callMe be called with a Foo object whose $att is 'hi'?
         */
        $sut = new SuT();
        $sut->testMe( $stub );
    }
}

最佳答案

即使问题已经完全回答(如何断言对象的属性作为参数传递给 mock)我认为值得注意的是 PHPUnit 支持传递给 with() 的回调约束。

在尝试找出如何对模拟对象参数运行进一步的断言时,我一直在与这个线程碰撞。例如,我需要检查某些方法的返回值。显然,为了理智起见,没有方法 ReturnValueEqualTo() 等同于上述答案中使用的属性断言。

幸运的是,PHPUnit 确实支持(至少从 3.7 开始)回调约束,这很有意义,您可以在像 Mockery 这样的专门 Mock 库中找到它。 .

当前 PHPUnit version docs说明如下:

The callback() constraint can be used for more complex argument verification. This constraint takes a PHP callback as its only argument. The PHP callback will receive the argument to be verified as its only argument and should return TRUE if the argument passes verification and FALSE otherwise.

因此,使用回调约束,OP 示例现在可以表示为:

class SuTTest extends PHPUnit_Framework_TestCase {
    public function testSuT () {
        $stub = $this->getMock('Some');
        $stub->expects($this->once())
            ->method('callMe')
            ->with($this->callback(function($arg) {
                    return ($arg instanceof Some) && ($arg->att === 'hi');
                })
            );

        /*
         * Will $stub->callMe be called with a Foo object whose $att is 'hi'?
         */
        $sut = new SuT();
        $sut->testMe($stub);
    }
}

测试失败看起来像这样:

1) SuTTest::testSuT
Expectation failed for method name is equal to <string:callMe> when invoked 1 time(s)
Parameter 0 for invocation Some::callMe(Foo Object (...)) does not match expected value.
Failed asserting that Foo Object () is accepted by specified callback.

您现在可以对该参数运行任何逻辑。

更好的是,尽管 PHPUnit 文档中没有记录功能,但您实际上可以使用断言并获得断言错误消息的好处:

class SuTTest extends PHPUnit_Framework_TestCase {
    public function testSuT () {
        // alias to circumvent php closure lexical variable restriction
        $test = $this;
        // proceed as normal
        $stub = $this->getMock('Some');
        $stub->expects($this->once())
            ->method('callMe')
            // inject the test case in the closure
            ->with($this->callback(function($arg) use ($test) {
                    // use test assertions
                    $test->assertInstanceOf('Some', $arg);
                    $test->assertAttributeEquals('hi', 'att', $arg);
                    // return true to satisfy constraint if all assertions passed
                    return true;
                })
            );

        /*
         * Will $stub->callMe be called with a Foo object whose $att is 'hi'?
         */
        $sut = new SuT();
        $sut->testMe( $stub );
    }
}

真的不知道这种使用断言并返回 true 的策略 future 如何证明。它没有记录,并且在错误消息中有一个权衡。您不再收到参数约束消息,因此如果您对多个参数设置断言,您将不得不推断,如果可能的话,哪个失败了。但是您确实可以更好地描述闭包内的失败断言。

1) SuTTest::testSuT
Expectation failed for method name is equal to <string:callMe> when invoked 1 time(s)
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'hi'
+'no'

希望这对遇到类似问题的人有所帮助。

关于php - 如何断言模拟对象的函数调用的对象参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5962514/

相关文章:

php - 如何在 cpanel 中设置 cron 作业

php - 在为该对象编写类之前为该对象编写模拟/ stub ?

php - Laravel 在测试具有许多依赖项的模型之前准备数据库,有没有更好的方法?

php - 使用 QuickBooks PHP Dev Kit/QuickBooks Web Connector 从 QuickBooks 导入项目

php - fopen()/fputcsv() : error

javascript - 显示多个上传文件的总大小

php - 在 PHPUnit 中模拟时在回调中通过引用传递

php - Laravel PHPUnit 返回 404

laravel - 如何为使用 Laravel 5 中存储文件系统的端点编写集成测试?

php - 编辑 : Class Zend\Db\Adapter\Adapter not found