测试抽象类

时间:2008-10-10 06:03:08

标签: unit-testing phpunit abstract-class

如何使用PHPUnit测试抽象类的具体方法?

我希望我必须创建某种对象作为测试的一部分。虽然,我不知道最好的做法,或者如果PHPUnit允许这样做。

6 个答案:

答案 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());
    }
}

模拟对象为您提供了几点:

  • 您不需要具体抽象类的实现,而是可以使用存根而不是
  • 您可以调用具体方法并断言它们正确执行
  • 如果具体方法依赖于未实现的(抽象)方法,则可以使用will()PHPUnit方法存根返回值

答案 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抽象类。