Testing Abstract Classes
如何用phpunit测试抽象类的具体方法?
我希望作为测试的一部分,我必须创建某种对象。不过,我不知道这方面的最佳实践,也不知道phpunit是否允许这样做。
抽象类的单元测试并不意味着测试接口,因为抽象类可以有具体的方法,而这种具体的方法可以被测试。
在编写一些库代码时,拥有您希望在应用程序层中扩展的某些基类并不少见。如果你想确保库代码是经过测试的,你需要一些方法来测试抽象类的具体方法。
就个人而言,我使用phpunit,它有所谓的存根和模拟对象来帮助您测试这类东西。
直接从phpunit手册:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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()); } } |
模拟对象为您提供以下几种功能:
- 您不需要有抽象类的具体实现,可以用存根来代替。
- 您可以调用具体的方法并断言它们的性能是正确的
- 如果具体方法依赖于未实现(抽象)方法,则可以使用will()phpunit方法来存根返回值。
这是个好问题。我也一直在找这个。幸运的是,phpunit已经为这个案例提供了
1 2 3 4 5 | protected function setUp() { $stub = $this->getMockForAbstractClass('Some_Abstract_Class'); $this->_object = $stub; } |
重要:
注意,这需要phpunit>3.5.4。在以前的版本中有一个错误。
要升级到最新版本:
1 2 | sudo pear channel-update pear.phpunit.de sudo pear upgrade phpunit/PHPUnit |
应该注意的是,截至php 7,已经添加了对匿名类的支持。这为您提供了一种为抽象类设置测试的额外方法,一种不依赖于phpunit特定功能的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 } |
纳尔逊的回答是错误的。
抽象类并不要求它们的所有方法都是抽象的。
实现的方法是我们需要测试的方法。
您可以做的是在单元测试文件上创建一个假存根类,让它扩展抽象类,并且只实现完全没有功能的所需内容,当然,还要测试它。
干杯。
Eran,您的方法应该有效,但是它违背了在实际代码之前编写测试的趋势。
我建议您编写有关抽象类的非抽象子类所需功能的测试,然后编写抽象类和实现子类,最后运行测试。
显然,您的测试应该测试抽象类的定义方法,但总是通过子类。
如果您不想将抽象类子类化,只是为了对已经在抽象类中实现的方法执行单元测试,那么您可以尝试查看您的框架是否允许您模拟抽象类。