测试抽象类

发布于 2024-07-06 15:28:33 字数 99 浏览 8 评论 0原文

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

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

How do I test the concrete methods of an abstract class with PHPUnit?

I'd expect that I'd have to create some sort of object as part of the test. Though, I've no idea the best practice for this or if PHPUnit allows for this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

巷雨优美回忆 2024-07-13 15:28:33

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

在编写一些库代码时,希望在应用程序层中扩展某些基类的情况并不少见。 如果您想确保库代码经过测试,您需要对抽象类的具体方法进行 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 方法

Unit testing of abstract classes doesn't necessary mean testing the interface, as abstract classes can have concrete methods, and this concrete methods can be tested.

It is not so uncommon, when writing some library code, to have certain base class that you expect to extend in your application layer. And if you want to make sure that library code is tested, you need means to UT the concrete methods of abstract classes.

Personally, I use PHPUnit, and it has so called stubs and mock objects to help you testing this kind of things.

Straight from 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());
    }
}

Mock object give you several things:

  • you are not required to have concrete implementation of abstract class, and can get away with stub instead
  • you may call concrete methods and assert that they perform correctly
  • if concrete method relies to unimplemented (abstract) method, you may stub the return value with will() PHPUnit method
烟火散人牵绊 2024-07-13 15:28:33

应该注意的是,从 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
}

It should be noted that as of PHP 7 support for anonymous classes has been added. This gives you an additional avenue for setting up a test for an abstract class, one that doesn't depend on PHPUnit-specific functionality.

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
}
把时间冻结 2024-07-13 15:28:33

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

That's a good question. I've been looking for this too.
Luckily, PHPUnit already has getMockForAbstractClass() method for this case, e.g.

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

Important:

Note that this requires PHPUnit > 3.5.4. There was a bug in previous versions.

To upgrade to the newest version:

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit
听,心雨的声音 2024-07-13 15:28:33

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

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

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

Eran, your method should work, but it goes against the tendency of writing the test before the actual code.

What I would suggest is to write your tests on the desired functionality of a non-abstract subclass of the abstract class in question, then write both the abstract class and the implementing subclass, and finally run the test.

Your tests should obviously test the defined methods of the abstract class, but always via the subclass.

同尘 2024-07-13 15:28:33

纳尔逊的回答是错误的。

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

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

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

干杯。

Nelson's answer is wrong.

Abstract classes don't require all of their methods to be abstract.

The implemented methods are the ones we need to test.

What you can do is create a fake stub class on the unit test file, have it extend the abstract class and implement only what's required with no functionality at all, of course, and test that.

Cheers.

若能看破又如何 2024-07-13 15:28:33

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

If you do not want to subclass the abstract class just to perform a unit test on the methods which are implemented in the abstract class already, you could try to see whether your framework allows you to mock abstract classes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文