152

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

我希望我必须创建某种对象作为测试的一部分。虽然,我不知道这个的最佳实践,或者 PHPUnit 是否允许这样做。

4

6 回答 6

252

抽象类的单元测试并不一定意味着测试接口,因为抽象类可以有具体的方法,而这个具体的方法是可以测试的。

在编写一些库代码时,具有某些您希望在应用程序层中扩展的基类并不少见。而且,如果您想确保库代码经过测试,您需要使用 UT 抽象类的具体方法的方法。

就我个人而言,我使用 PHPUnit,它有所谓的存根和模拟对象来帮助您测试这类事情。

直接来自PHPUnit 手册

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 方法存根返回值
于 2010-02-10T23:35:03.847 回答
42

应该注意的是,从 PHP 7 开始,添加了对匿名类的支持。这为您为抽象类设置测试提供了另一种途径,它不依赖于 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
}
于 2018-02-20T15:47:01.850 回答
39

这是个好问题。我也一直在找这个。
幸运的是,PHPUnit 已经有getMockForAbstractClass()这种情况的方法,例如

protected function setUp()
{
    $stub = $this->getMockForAbstractClass('Some_Abstract_Class');
    $this->_object = $stub;
}

重要的:

请注意,这需要 PHPUnit > 3.5.4。以前的版本中有一个错误

要升级到最新版本:

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit
于 2011-02-13T23:46:54.910 回答
1

Eran,您的方法应该可以工作,但它违背了在实际代码之前编写测试的趋势。

我的建议是在所讨论的抽象类的非抽象子类的所需功能上编写测试,然后编写抽象类和实现子类,最后运行测试。

您的测试显然应该测试抽象类的定义方法,但总是通过子类。

于 2008-11-12T18:48:10.630 回答
1

尼尔森的回答是错误的。

抽象类并不要求它们的所有方法都是抽象的。

实现的方法是我们需要测试的。

您可以做的是在单元测试文件上创建一个假存根类,让它扩展抽象类并仅实现所需的功能,当然,并对其进行测试。

干杯。

于 2009-09-23T15:19:58.793 回答
0

如果您不想子类化抽象类只是为了对已经在抽象类中实现的方法执行单元测试,您可以尝试查看您的框架是否允许您模拟抽象类。

于 2008-11-12T19:06:25.163 回答