如何测试工厂类?

Mat*_*oli 5 php testing unit-testing design-patterns

给定这个类:

class MyBuilder {
    public function build($param1, $param2) {

        // build dependencies ...

        return new MyClass($dep1, $dep2, $dep3);
    }
}
Run Code Online (Sandbox Code Playgroud)

我如何对这个类进行单元测试?

单元测试意味着我想测试它的行为,所以我想测试它使用正确的依赖项构建我的对象。但是,那new指令是硬编码的,我无法模拟它。

现在,我添加了类的名称作为参数(这样我就可以提供模拟类的类名),但它很丑陋:

class MyBuilder {
    public function build($classname, $param1, $param2) {

        // build dependencies ...

        return new $classname($dep1, $dep2, $dep3);
    }
}
Run Code Online (Sandbox Code Playgroud)

是否有一个干净的解决方案或设计模式可以使我的工厂可测试?

hak*_*kre 1

那么你想测试什么?

所以我想测试它是否使用正确的依赖项构建我的对象。

我确实看到了这个问题。您可能会创建一个具有不正确依赖项的对象(首先不应该是这种情况,或者在其他测试中进行测试,而不是在工厂中进行测试),或者您想要测试不应该测试的工厂的详细信息全部。

否则 - 如果它不是嘲笑工厂你正在寻找的东西 - 我认为没有理由为什么一个简单的

$actual = $subject->build($param1, $param2);
$this->assertInstanceOf('MyClass', $actual);
Run Code Online (Sandbox Code Playgroud)

不会成功的。它测试工厂构建方法的行为,以确保它返回正确的类型。

另请参见开闭原则


对于测试,您可以创建从 Builder 扩展的 MockBuilder:

class MyMockBuilder extends MyBuilder {
    public function build($param1, $param2) {

        // build dependencies ...

        return new MyMockClass($dep1, $dep2, $dep3);
    }
}
Run Code Online (Sandbox Code Playgroud)

让类名成为参数 1:1 对我来说似乎不切实际,因为它将工厂变成了不同的东西。创建是工厂的一个细节,没有任何外部化的内容。所以应该封装起来。因此使用 MockBuilder 进行测试。你切换工厂。