简体   繁体   English

phpunit与嘲讽-如何测试带有适当参数的嘲笑对象

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

So I'm writing tests for a php api consumer library. 因此,我正在为php api使用者库编写测试。 In one of the main libraries main functions I have: 在主要库之一中,我具有:

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

In my test I'm using mockery and doing something like: 在我的测试中,我使用嘲讽并做类似的事情:

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

this is properly overloading my Schema class with a mock. 这可以通过模拟正确地重载我的Schema类。 So later when I do: 因此,当我这样做时:

$myclass->movies()

It should call the __call method, thus calling the mocked Schema class. 它应该调用__call方法,从而调用模拟的Schema类。 This all seems good so far, but I would like to assert that the $schemaMock is being constructed with the name of the function, in this case movies as well as the instance of the class being passed in. What I've tried is: 到目前为止,这一切似乎都不错,但是我想断言$ schemaMock是使用函数名构造的,在这种情况下,是movies以及传入的类的实例。我尝试过的是:

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

However my tests pass regardless of what the "with" function argument states. 但是,无论“ with”函数参数声明什么,我的测试都会通过。 IE I can change movies to foobar and tests still pass. IE浏览器,我可以将movies更改为foobar并且测试仍然可以通过。 I'm sure I'm missing something simple about how to run these assertions. 我确定我缺少有关如何运行这些断言的简单信息。 Thanks for any help! 谢谢你的帮助!

Short and final answer: you can't. 简短而最终的答案: 您不能。

A mock is defined by cobbling together code for a new class. 通过将新类的代码合并在一起来定义模拟。 It contains methods for all mocked methods, and for all others, it is a child class that implements the original class as its parent. 它包含所有模拟方法的方法,对于所有其他方法,它是将原始类实现为其父类的子类。 The mock class contains no constructor - for normal mock objects, the parent gets called. 模拟类不包含构造函数-对于普通模拟对象,父类会被调用。 That is the way constructor arguments passed to Mockery::mock($class, $args) get considered. 这就是传递给Mockery::mock($class, $args)构造函数参数的方式。

But for instance mocks, a constructor for copied mocks is needed. 但是对于模拟,例如,需要一个用于复制模拟的构造函数。 It is hidden pretty deep inside the source, but if you look at mockery/library/Mockery/Generator/StringManipulation/Pass/InstanceMockPass.php , you can see that the only purpose of that method is to copy properties and expectations over to the new instance. 它隐藏在源代码的很深处,但是如果您查看mockery/library/Mockery/Generator/StringManipulation/Pass/InstanceMockPass.php ,则可以看到该方法的唯一目的是将属性和期望复制到新的实例。 Arguments are simply ignored. 参数将被忽略。

The best approximation you could get would be to wrap your instantiation call in a mockable method that does nothing besides creating an instance with the arguments from the method - like here : 你可以得到最好的逼近将包装你的实例调用中,什么也不做,除了从方法的参数创建实例的mockable方法-就像这里

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

        return $ref->newInstanceArgs( $args );
    }
}

or to delegate the real instantiation task from the constructor to a mockable method: 或将实际的实例化任务从构造函数委托给可模拟的方法:

class Schema {

    public function __construct () {
        call_user_func_array( array( $this, 'init' ), func_get_args() );
    }

    public function init ($name, $obj) {
        //...
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM