为接口编写一个测试类,并使用工厂测试对象


PHPUnit - Writing a test class for an interface, and testing objects using a factory

我正在编写一个将继承接口的类。将为该接口编写客户端代码,并编写类来支持它。我的想法是,稍后我将为该接口编写其他类,并且这两个不同类的对象应该完全可互换。比起为第一个类编写测试类,我想为接口编写一个测试类。

我的计划是编写一个测试类,它将为构造函数(依赖注入)接受一个工厂对象,并使用工厂来创建被测试类的新实例。

这样,如果我想测试ClassA,我可以传递一个ClassAFactory对象给测试类的构造函数,如果我想测试ClassB,我可以传递一个ClassBFactory对象。这两个类被设计为可互换的,并且由于只测试公共方法,因此这似乎是理想的。

但是测试构造函数呢?我会更好地编写一个抽象测试类,并在继承抽象测试类的类中实现构造函数测试(不同的类可能以不同的方式实例化)?

如果我确实使用了第一个想法,我想我将为每个被测试的类创建一个测试类,如:

class ClassATest extends [PHPUnit test case]
{
    $myFactory = new ClassAFactory();
    $myTest = new ClassTest($myFactory);
    $myTest->test1();
    $myTest->test2();
    //etc.
}

做这件事最好的方法是什么?我希望有一个通用的测试,这样当我编写新类来实现公共接口时,我就可以将用于其他测试的相同测试对象放入其中。但是,考虑到不同的类将有不同的构造函数,也许编写一个抽象测试类并为每个新对象扩展它会更好?你觉得呢?

我认为你需要重新考虑你的计划。你不能测试接口,这有一个很好的理由——接口只是定义API而不是功能,测试测试功能。让我给你举个例子,也许会有所帮助。假设您有一个"消息传递"接口。你实现了一个EmailMessager和一个SMSMessager。现在您需要单独测试这些,就像使用EmailMessager一样,您需要确保它正在做它的事情,可能验证收件人(电子邮件地址),并可能将发送委托给电子邮件类等。显然,短信就不一样了。

您可以使用每个子类无需工厂即可设置的属性来创建包含所有测试方法的抽象测试用例。它可以测试所有实现必须具备的固定质量。

abstract class IAdderTestCase extends PFTC
{
    function testAdd() {
        self::assertEquals(5, $this->fixture->add(2, 3));
    }
    ...
}
class BasicAdderTest extends IAdderTestCase
{
    function setUp() {
        $this->fixture = new BasicAdder();
    }
}

PHPUnit将在每个测试方法之前调用setUp()。它应该为每个具体子类调用所有继承的测试方法以及任何附加的测试方法,例如测试构造函数。