【发布时间】:2011-12-23 19:51:57
【问题描述】:
有没有什么好的方法可以使用 PHPUnit 模拟抽象类中的具体方法?
到目前为止我发现的是:
- expects()->will() 使用抽象方法可以正常工作
- 它不适用于具体方法。而是运行原始方法。
- 使用 mockbuilder 并将所有抽象方法和具体方法提供给 setMethods() 有效。但是,它需要您指定所有抽象方法,这使得测试变得脆弱且过于冗长。
- MockBuilder::getMockForAbstractClass() 忽略 setMethod()。
以下是一些对上述几点进行示例的单元测试:
abstract class AbstractClass {
public function concreteMethod() {
return $this->abstractMethod();
}
public abstract function abstractMethod();
}
class AbstractClassTest extends PHPUnit_Framework_TestCase {
/**
* This works for abstract methods.
*/
public function testAbstractMethod() {
$stub = $this->getMockForAbstractClass('AbstractClass');
$stub->expects($this->any())
->method('abstractMethod')
->will($this->returnValue(2));
$this->assertSame(2, $stub->concreteMethod()); // Succeeds
}
/**
* Ideally, I would like this to work for concrete methods too.
*/
public function testConcreteMethod() {
$stub = $this->getMockForAbstractClass('AbstractClass');
$stub->expects($this->any())
->method('concreteMethod')
->will($this->returnValue(2));
$this->assertSame(2, $stub->concreteMethod()); // Fails, concreteMethod returns NULL
}
/**
* One way to mock the concrete method, is to use the mock builder,
* and set the methods to mock.
*
* The downside of doing it this way, is that all abstract methods
* must be specified in the setMethods() call. If you add a new abstract
* method, all your existing unit tests will fail.
*/
public function testConcreteMethod__mockBuilder_getMock() {
$stub = $this->getMockBuilder('AbstractClass')
->setMethods(array('concreteMethod', 'abstractMethod'))
->getMock();
$stub->expects($this->any())
->method('concreteMethod')
->will($this->returnValue(2));
$this->assertSame(2, $stub->concreteMethod()); // Succeeds
}
/**
* Similar to above, but using getMockForAbstractClass().
* Apparently, setMethods() is ignored by getMockForAbstractClass()
*/
public function testConcreteMethod__mockBuilder_getMockForAbstractClass() {
$stub = $this->getMockBuilder('AbstractClass')
->setMethods(array('concreteMethod'))
->getMockForAbstractClass();
$stub->expects($this->any())
->method('concreteMethod')
->will($this->returnValue(2));
$this->assertSame(2, $stub->concreteMethod()); // Fails, concreteMethod returns NULL
}
}
【问题讨论】:
-
您不需要测试抽象类,因为它们是抽象的。还是你也想写一个抽象的测试用例?
-
抽象类是另一个类的依赖。所以我想测试使用 $object->concreteMethod() 的 SomeClass::getMyCalculatedValue()。由于concreteMethod() 可以更改或可能难以设置,我想指定concreteMethod() 的返回值。
标签: php unit-testing mocking phpunit