考虑
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 );
}
}
答案 0 :(得分:10)
即使问题已经完全回答(如何断言作为参数传递给mock的对象的属性)我认为值得注意的是PHPUnit支持将回调约束传递给with()。
在尝试找出如何在模拟对象参数上运行进一步的断言时,我一直在讨论这个线程。例如,我需要检查某些方法的返回值。显然,为了理智,没有methodReturnValueEqualTo()等效于上面答案中使用的属性断言。
幸运的是,PHPUnit确实支持(至少3.7)一个回调约束,这很有意义,你可以在像Mockery这样的专业模拟库中找到它。
当前PHPUnit version docs声明以下内容:
callback()约束可用于更复杂的参数验证。此约束将PHP回调作为其唯一参数。 PHP回调将接收要验证的参数作为其唯一参数,如果参数通过验证则应返回TRUE,否则返回FALSE。
因此,使用回调约束,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
方法名称的期望失败等于< string:callMe>当被调用1次时 参数0用于调用Some :: callMe(Foo Object(...))与期望值不匹配 声明Foo Object()被指定的回调接受失败。
您现在可以在该参数上运行任何逻辑。
更好的是,尽管不是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 的策略的未来证明。它没有记录,并且在错误消息中存在折衷。您不再获取参数约束消息,因此如果您在多个参数上设置断言,则必须推断哪一个失败。但是你确实可以更好地描述闭包内失败的断言。
1)SuTTest :: testSuT
方法名称的期望失败等于< string:callMe>当被调用1次时 声明两个字符串相等的失败 ---预期
+++实际
@@ @@
-'hi“
+'不'
希望这可以帮助任何面临类似问题的人。
答案 1 :(得分:8)
您只需将期望值传递给“with”方法。
->with(1, $object, "paramThree");
你也可以传入一系列phpUnit断言而不是参数(默认等于)
->with(1, $this->equalTo($object), "paramThree");
所以对于对象,您可以使用$this->isInstanceOf("stdClass")
作为->with
的参数
对于可能的断言列表,请查看:PHPUnit/Framework/Assert.php
表示返回new PHPUnit_Framework_Constraint
第一个测试用例只匹配2个参数并且工作
第二个匹配两个并且在参数2上失败
最后一个测试传入的对象的类型为stdClass
<?php
class MockMe {
public function bla() {
}
}
class Demo {
public function foo(MockMe $x) {
$x->bla(1, 2);
}
public function bar(MockMe $x) {
$x->bla(1, new stdClass());
}
}
class DemoTest extends PHPUnit_Framework_TestCase {
public function testWorks() {
$x = new Demo();
$mock = $this->getMock("MockMe");
$mock->expects($this->once())->method("bla")->with(1,2);
$x->foo($mock);
}
public function testFails() {
$x = new Demo();
$mock = $this->getMock("MockMe");
$mock->expects($this->once())->method("bla")->with(1,3);
$x->foo($mock);
}
public function testObject() {
$x = new Demo();
$mock = $this->getMock("MockMe");
$mock->expects($this->once())->method("bla")->with(1, $this->isInstanceOf("stdClass"));
$x->bar($mock);
}
}
phpunit DemoTest.php
PHPUnit 3.5.13 by Sebastian Bergmann.
.F.
Time: 0 seconds, Memory: 4.25Mb
There was 1 failure:
1) DemoTest::testFails
Failed asserting that <integer:2> matches expected <integer:3>.
...DemoTest.php:12
...DemoTest.php:34
FAILURES!
Tests: 3, Assertions: 2, Failures: 1.
答案 2 :(得分:7)
这是一个可以满足您需求的简单示例:
$mock->expects ($this->once())
->method ('dummyFunction')
->with ($this->logicalAnd ($this->isInstanceOf ('DummyClass')
,$this->attributeEqualTo ('attribute1', 1001)
,$this->attributeEqualTo ('attribute2', 200)))
->will ($this->returnValue (null));
代码的其余部分:
class DummyClass {
private $attribute1 = 1001;
private $attribute2 = 200;
}
function dummyFunction (DummyClass $p) {...}
dummyFunction (new DummyClass());
我希望我帮助过你