Phpunit with mock -如何测试用适当的参数构造一个mock对象


phpunit with mockery - how to test a mocked object is constructed with proper arguments

所以我正在为php api消费者库编写测试。在一个主要的库中,我有main函数:

public function __call($name, $args) {
    return new Schema($name, $this);
}

在我的测试中,我使用了嘲弄,并做了这样的事情:

$schemaMock = m::mock('overload:Mynamespace'Schema');

用mock适当地重载我的Schema类。所以之后当我输入:

$myclass->movies()

它应该调用__call方法,从而调用模拟的Schema类。到目前为止,这一切似乎都很好,但我想断言,$schemaMock是用函数的名称构造的,在本例中是movies以及传递进来的类的实例。我试过的是:

$schemaMock->shouldReceive('__construct')->with('movies');

然而,无论"with"函数参数是什么,我的测试都通过了。IE我可以将movies改为foobar,测试仍然通过。关于如何运行这些断言,我肯定遗漏了一些简单的东西。谢谢你的帮助!

简短的最后回答:你不能。

通过将新类的代码拼凑在一起来定义mock。它包含所有模拟方法的方法,对于所有其他方法,它是一个子类,将原始类实现为其父类。模拟类不包含构造函数——对于普通的模拟对象,调用父类。这就是传递给Mockery::mock($class, $args)的构造函数参数被考虑的方式。

但是对于实例mock,需要复制mock的构造函数。它隐藏在源代码的深处,但是如果您查看mockery/library/Mockery/Generator/StringManipulation/Pass/InstanceMockPass.php,您可以看到该方法的唯一目的是将属性和期望复制到新实例中。参数被直接忽略。

你能得到的最好的近似是把你的实例化调用包装在一个可模拟的方法中,这个方法除了用方法的参数创建一个实例之外什么都不做——就像下面这样:

public function instantiate ( $name, $args=array() ) {
    if ( empty($args) )
        return new $name();
    else {
        $ref = new ReflectionClass( $name );
        return $ref->newInstanceArgs( $args );
    }
}

或将实际的实例化任务从构造函数委托给可模拟的方法:

class Schema {
    public function __construct () {
        call_user_func_array( array( $this, 'init' ), func_get_args() );
    }
    public function init ($name, $obj) {
        //...
    }
}