如何单元测试实例创建?

时间:2009-12-14 11:26:26

标签: unit-testing dependency-injection

我有一个Carpenter课程,可以使用LatheWood对象完成工作。

class Carpenter
{
    function Work()
    {
        $tool = new Lathe();
        $material = new Wood();
        $tool->Apply($material);
    }
}

Lathe取决于名为Material的界面,因此我可以通过在单元测试中给出假Lathe来轻松单元测试MaterialWood不依赖于任何东西,因此也可以轻松测试。

interface Material {
    // Various methods...
}

interface Tool {
    function Apply(Material $m);
}

class Wood implements Material  {
    // Implementations of Material methods
}

class Lathe {
    function Apply(Material $m) {
        // Do processing
    }
}

但是,Carpenter取决于具体的类LatheWood,因为它必须创建它们的实例。这意味着,就目前而言,我无法对Work()方法进行单元测试,而不会无意中将LatheWood置于测试之中。

如何将我的设计更改为单元测试Carpenter

2 个答案:

答案 0 :(得分:5)

您可以在这里找到几个不同的方向:

  • 使用构造函数注入,只需将工具和材质实例注入木匠。
  • 如果注入实例由于某种原因不起作用(可能是因为您需要为每次调用Work方法创建新实例),您可以注入抽象工厂
  • 您也可以使用ctford描述的工厂方法方法,但这需要您创建特定于测试的覆盖才能进行单元测试,而这是完全有效的事情,这只是更多的工作,在许多情况下,其他选择更好,更灵活。

答案 1 :(得分:3)

关键是在Carpenter中分离对象的使用。

class Carpenter
{
    function getTool() {
        return new Lathe();
    }
    function getMaterial() {
        return new Wood();
    }
    function Work()
    {
        $tool = getTool();
        $material = getMaterial();
        $tool->Apply($material);
    }
}

这样您就可以覆盖getTool()课程中的getMaterial()TestCarpenter方法,并注入自己的MaterialTool个假货。

getTool()getMaterial()方法也可以单独进行单元测试。

Michael Feathers会调用getTool()getMaterial()方法“接缝”,因为它们是可以在不更改周围代码的情况下插入假货的点。

相关问题