如何使用PHPUnit测试抽象类的具体方法?
我希望我必须创建某种对象作为测试的一部分。虽然,我不知道最好的做法,或者如果PHPUnit允许这样做。
答案 0 :(得分:228)
抽象类的单元测试不一定意味着测试接口,因为抽象类可以有具体的方法,并且可以测试这些具体的方法。
在编写一些库代码时,为了拥有您希望在应用程序层中扩展的某个基类,这种情况并不少见。如果你想确保库代码经过测试,你需要使用UT来抽象类的具体方法。
我个人使用PHPUnit,它有所谓的存根和模拟对象来帮助你测试这类东西。
直接来自PHPUnit manual:
abstract class AbstractClass
{
public function concreteMethod()
{
return $this->abstractMethod();
}
public abstract function abstractMethod();
}
class AbstractClassTest extends PHPUnit_Framework_TestCase
{
public function testConcreteMethod()
{
$stub = $this->getMockForAbstractClass('AbstractClass');
$stub->expects($this->any())
->method('abstractMethod')
->will($this->returnValue(TRUE));
$this->assertTrue($stub->concreteMethod());
}
}
模拟对象为您提供了几点:
答案 1 :(得分:36)
这是一个很好的问题。我也一直在寻找这个
幸运的是,PHPUnit在这种情况下已经有getMockForAbstractClass()
方法,例如
protected function setUp()
{
$stub = $this->getMockForAbstractClass('Some_Abstract_Class');
$this->_object = $stub;
}
请注意,这需要PHPUnit> 3.5.4。在以前的版本中有a bug。
要升级到最新版本:
sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit
答案 2 :(得分:20)
应该注意的是,自PHP 7起,已添加对anonymous classes的支持。这为您为抽象类设置测试提供了额外的途径,该抽象类不依赖于PHPUnit特定的功能。
class AbstractClassTest extends \PHPUnit_Framework_TestCase
{
/**
* @var AbstractClass
*/
private $testedClass;
public function setUp()
{
$this->testedClass = new class extends AbstractClass {
protected function abstractMethod()
{
// Put a barebones implementation here
}
};
}
// Put your tests here
}
答案 3 :(得分:1)
Eran,你的方法应该有效,但它违背了在实际代码之前编写测试的倾向。
我建议将测试编写在有问题的抽象类的非抽象子类的所需功能上,然后编写抽象类和实现子类,最后运行测试。
您的测试显然应该测试抽象类的已定义方法,但总是通过子类测试。
答案 4 :(得分:1)
尼尔森的回答是错误的。
抽象类不要求所有方法都是抽象的。
实施的方法是我们需要测试的方法。
你可以做的是在单元测试文件上创建一个虚假的存根类,让它扩展抽象类,然后只实现所需的功能,当然,并测试它。
干杯。
答案 5 :(得分:0)
如果您不想将抽象类子类化为仅对已在抽象类中实现的方法执行单元测试,您可以尝试查看您的框架是否允许您mock抽象类。