2009-12-14 101 views
4

我有一个Carpenter类,它使用LatheWood对象来工作。如何单元测试实例创建?

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

Lathe取决于称为Material在接口上,这样我就可以很容易地进行单元测试Lathe给它一个假Material在我的单元测试。 Wood不依赖于任何东西,所以它也可以很容易地测试。

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

回答

5

有几个不同的方向,你可以采取这里:

  • 使用构造器注入,只需注入工具和材料的情况下,进入木匠。
  • 如果由于某种原因注入实例不起作用(可能是因为您需要为每次调用Work方法创建新实例),则可以注入抽象工厂
  • 您也可以使用ctford描述的工厂方法方法,但这需要您创建特定于测试的覆盖以便能够进行单元测试,尽管这是一个完全有效的事情,但它只是更多的工作而已在很多情况下,其他方案更好,更灵活。
+0

有趣。但是,如果你注入一个抽象工厂,是不是只是将单元测试问题转移到创建抽象工厂并将其注入到Carpenter中的方法中?谢谢你的帮助。 – ctford 2009-12-15 09:42:12

+0

不,因为使用抽象工厂将对象创建从行为中分离出来,这意味着您可以对每个对象进行单元测试。 – 2009-12-15 11:43:41

+0

您可以对抽象工厂本身进行单元测试,但创建抽象工厂并将其提供给木匠的方法与原始问题中的问题相同。你必须找出一种方法将测试抽象工厂注入到该方法中(并且我认为抽象工厂工厂不会成为下一步:) ......对吗? – ctford 2009-12-15 13:30:39

3

关键是要在对象使用Carpenter中分离创建对象。

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

这样,你可以覆盖在TestCarpentergetTool()getMaterial()方法和注入自己的MaterialTool假货。

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

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

相关问题