phpunit with mockery - 如何测试一个模拟对象是用适当的参数构造的

时间:2015-06-05 21:11:48

标签: php unit-testing phpunit mockery

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

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

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

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

这正好用模拟重载我的Schema类。所以后来当我这样做时:

$myclass->movies()

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

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

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

1 个答案:

答案 0 :(得分:0)

简短且最终答案:你不能。

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

但是例如模拟,需要复制模拟的构造函数。它隐藏在源代码内部,但是如果你看一下mockery/library/Mockery/Generator/StringManipulation/Pass/InstanceMockPass.php,你会发现该方法的唯一目的是将属性和期望复制到新实例。参数被忽略了。

您可以获得的最佳近似是将实例化调用包装在一个可模拟的方法中,除了使用方法中的参数创建实例之外什么都不做 - 比如here

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) {
        //...
    }
}