2017-02-13 106 views
0

單元測試開始,我不知道如何測試我們的老代碼,這看起來就像這樣:單元測試方法具有依賴性(無接口)

public Player DetermineWinner(Player a, Player b) 
{ 
    if(a.Age>b.Age) 
    .... 
    ///few more conditions checking properties of both players 
} 

class Player 
{ 
    public Player (DBConnection c, world w, DateTime logTime) 
    {} //not easy to mock... 
} 

如何嘲笑呢?我明白,如果Player實現了一個接口,我可以簡單地創建一個模擬並將其傳遞到具有期望值的單元測試中,但這不是這種情況。 Player類使用各種參數實例化,所以我不能在單元測試期間簡單地創建一個實例並傳遞它 - 它取決於各種外部對象。 我需要模擬Player對象並同時設置它的屬性,以便測試是確定性的。開始的最佳方法是什麼?

下次我應該使用接口來解耦嗎?

+1

把類的所有依賴'Player'它使用了一些的外部資源('DbConnection'至少)背後的接口或使他們的方法是虛擬的。然後你可以用「模擬」依賴關係來測試'Player'類。其他方法使用一些「沒有限制」的嘲笑框架,它會爲你做 – Fabio

+0

這裏的*真實*問題不是「如何嘲笑」,而是被測試代碼的非常糟糕的設計。具體而言,'Player'類不應該依賴'DBConnection'。相反,它的構造函數只應該獲取真正屬於某個玩家的數據項,以及在其他地方讀取/寫入玩家數據的數據庫訪問權限。 –

+0

什麼是您的Visual Studio版本? – zaitsman

回答

0

我想你不明白嘲笑的真正含義。

A 嘲笑對象有沒有與該類的「真正」實現。它只是「看起來」像那個班的一個對象。

但是你(或嘲笑框架)在控制該對象的行爲。那麼,除非該字段是私人(請參閱here)。所以:當你的播放器字段不是私人的,你沒有問題。

沒有模擬框架 - 你真的不能做太多。如果有的話,你可以嘲諷作爲參數的所有對象被測試的類的構造函數。

換句話說:最後,你需要一些類「X」的對象「x」;當使用「真實」類「X」給你帶來很多麻煩時,你必須用看起來像「X」的東西來代替它。

最壞的情況下,你可能有兩個不同版本的X類;但那會讓事情變得非常複雜。

+0

是的,它看起來像一個,但是如何在單元測試期間創建它(假設沒有框架可用)?我會很感激例如使用我的代碼片段。 – user970696

+0

爲你提供一些更新,但我擔心沒有太多可以幫助你。當你不能修改源代碼,並且你不能使用模擬框架時,那麼你的內容有點破裂。 – GhostCat

1

你可以通過使用像Typemock這樣的框架來單元測試你的代碼而不用改變它,它可以讓你嘲笑具體的依賴關係而不需要添加接口,當你選擇一個類來模擬(在這種情況下,「Player」 typemock也會自動模擬其中的所有依賴關係)。

在你給出的例子:

public class UnitTest1 
    { 
     [TestMethod] 
     public void TestDetermineWinner_B_IsTheWinner() 
     { 
      var P1 = Isolate.Fake.Instance<Player>(); 
      var P2 = Isolate.Fake.Instance<Player>(); 

      Isolate.WhenCalled(() => P1.Age).WillReturn(0); 
      Isolate.WhenCalled(() => P2.Age).WillReturn(1); 

      var result = new ClassUnderTest().DetermineWinner(P1, P2); 

      Assert.AreEqual(P2, result); 
     } 
    } 
    public class ClassUnderTest 
    { 
     public Player DetermineWinner(Player a, Player b) 
     { 
      if (a.Age > b.Age) { return a; } 
      return b; 
     ///few more conditions checking properties of both players 
     } 
    } 
    public class Player 
    { 
     public Player(DbConnection c, world w, DateTime logTime) 
     { } //not easy to mock... 

     public int Age { get; internal set; } 
    } 
+0

你有點忘了提及,你必須支付Typemock :) – zaitsman

+0

但爲什麼它需要支付一些問題,讓你的生活更輕鬆? – JamesR

+0

由於購買VS企業更加謹慎 - >您可以獲得相同的功能,加上其他功能(如歷史調試,ADO.net跟蹤等) – zaitsman