2012-03-21 165 views
1

我想在方法運行一些單元測試,下面我傳遞一個嘲笑接口(vehicleObject)到ProcessVehicles但只要它是通過由DetermineVehicleType它被重新分配,所以我的嘲笑對象是無使用。我的第一個想法是創建一個布爾值,以確定是否應該運行DetermineVehicleType並將其添加爲參數,但聽起來非常混亂。有沒有更好的方法來解決這個問題?有沒有更好的方法來測試這種方法?

與模仿對象方法注入:

public void ProcessVehicles(ICarObject CarObject) 
{ 
    IObject vehicleObject = DetermineVehicleType(carObject); 
    vehicleObject.ProcessVehicle(carObject); 
} 

原始代碼:

public void ProcessVehicles() 
{ 
    IObject vehicleObject = DetermineVehicleType(carObject); 
    vehicleObject.ProcessVehicle(carObject); 
} 

注:我無法檢查vehicleObject調用DetermineVehicleType,因爲它可能不是空之前是空當班級被實際使用時。從長遠來看,也許總重構是答案,在這一點上,這不是我正在尋找的答案,也許沒有其他選擇。

方法DetermineVehicleType是私人

注:我知道有代碼異味,這是遺留代碼,目前的工作。我想得到它的測試不會改變它,所以它看起來很漂亮,然後停止生產。總重構可能是我唯一想確定模擬工具沒有另一個解決方案的唯一選擇。

+0

如果你模擬vehicleObject,你想測試什麼?如果ProcessVehicle被調用或什麼的? – 2012-03-21 19:27:18

+0

您能否詳細解釋ProcessVehicles方法的目標是什麼?我覺得這裏的代碼味道不好。通過將一個對象傳遞給一個函數並用一個以carObject作爲參數的函數改變它的引用。 – daryal 2012-03-21 19:28:02

+0

@WouterdeKort我想獲得測試方法ProcessVehicles – 2012-03-21 19:28:49

回答

3

什麼訪問修飾符DetermineVehicleType有?你可以把這個方法剔除,以便它返回你的模擬界面(Roy Osherove稱之爲abstract test driver pattern,我相信)。否則,這看起來像一個總理候選人重構:)

重構你的代碼,你會做這樣的事情

首先,改變你的方法簽名

protected virtual IObject DetermineVehicleType(CarObject obj) 
{ 
    //Do whatever you normally do 
} 

然後,在您的測試,你可以在上面的類中創建一個存根,並且無論傳入的是CarObject,它都會返回您的存根IObject。您可以通過繼承類來手動創建存根類,也可以使用MOQ之類的方法來完成此操作。讓我知道你是否需要我詳細說明這一點。

另要注意,但是:

一種更好的方式重構,這將是簡單地在IObject傳遞給ProcessVehicles,因爲它從這個例子,你在這裏有一個SRP違規行爲,其中ProcessVehicles方法似乎不僅僅是處理它們。不過,這也許就是剛剛從這個簡單的例子

全面實施更新

[Test] 
    public void TestMethod() 
    { 
     var testerStub = new TesterStub(); 
     testerStub.ProcessVehicles(); 
     //Assert something here 
    } 

    public class TesterStub : Tester 
    { 
     public override IObject DetermineVehicleType(CarObject obj) 
     { 
      var mockObject = new Mock<IObject>(); 
      mockObject.Setup(x => x.SomeMethod).Returns(Something); 
      return mockObject.Object; 
     } 
    } 

    public class Tester 
    { 
     protected virtual IObject DetermineVehicleType(CarObject obj) 
     { 
      return new ObjectTester(); 
     } 

     public void ProcessVehicles() 
     { 
      var carType = DetermineVehicleType(new CarObject()); 

     } 
    } 

    public class ObjectTester : IObject 
    { 
    } 

    public interface IObject 
    { 
    } 

    public class CarObject 
    { 
    } 
+0

答案更新...有關如何重構的任何想法? – 2012-03-21 19:27:27

+1

更新後再解釋一點。 – 2012-03-21 19:38:49

+0

是的,我同意在我重構項目之前,有很多違規行爲是我想要獲得項目的。你能詳細闡述一下你的重構想法嗎? – 2012-03-21 19:42:06

1

如果我們是非常字面,相信你的代碼演示了氣味。

請考慮:方法ProcessVehicles在名爲DetermineVehicleType的實例上調用方法。你的班級做什麼?請問Process Vehicles,還是Determine Vehicle Type?這對我來說表示違反了SRP,如果你從字面上理解。你的班正在努力做不止一份工作。

可以說這意味着SRP不贊成私人幫手方法。有些評論員確實認爲這是事實。我不確定我是否確定;一如既往,常識是關鍵。

如果我要重構這段代碼,我會給這個班級做個類似IVehicleCategoryHelper的公開DetermineVehicleType。也許這將通過它的構造函數傳遞,或者如果我們正在實現完全開發的Fat依賴注入,則需要一個IFactory,以便實例可以在需要時根據上下文檢索IVehicleCategoryHelper。

把一切我說過的一撮鹽。我不一定相信這是正確的方法 - 它最終取決於你自己決定。

+0

已編輯的問題 – 2012-03-21 20:00:51

相關問題