2009-12-14 98 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()方法「接縫」,因爲它們是可以在不改變周圍代碼的情況下插入假貨的點。

相關問題