测试抽象类


Answers:


240

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

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

我个人使用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方法对返回值进行存根

38

这是个好问题。我也一直在寻找。
幸运的是,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

听起来很有趣,但您会针对该模拟进行测试吗?测试是什么样的?IE:在测试用例中扩展模拟并针对扩展的测试类进行测试?
stefgosselin 2011年

34

应当注意,从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
}

4
谢谢你!在PHPUnit中使用匿名类为我创建各种测试提供了很大的灵活性。
爱丽丝·邦德

1

Eran,您的方法应该可以使用,但是这与在实际代码之前编写测试的趋势背道而驰。

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

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


我找到一个任意答案:您有一个具有通用'foo()'方法的抽象类'A'。整个“ B”和“ C”类都使用此“ foo()”方法,这两个类均从“ A”派生。您将选择哪个类来测试'foo()'?
user3790897 '17

1

尼尔森的答案是错误的。

抽象类不需要其所有方法都是抽象的。

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

您可以做的是在单元测试文件上创建一个伪造的存根类,让它扩展抽象类并仅实现所需的内容,而没有任何功能,然后进行测试。

干杯。


0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.