2014-12-28 26 views
3

我有以下測試:使用FakeItEasy,是有可能創造一個類型,採用一般類型的虛擬對象參數

[Fact] 
public void StartProgram_CallsZoneProgramStart() 
{ 
    var zone = A.Fake<Zone>(); 
    zone.StartProgram(); 
    A.CallTo(() => zone.ZoneProgram.Start(null, A.Dummy<ActionBlock<InterruptInfo>>())).MustHaveHappened(Repeated.Exactly.Once); 
} 

這是創造它被傳遞到MustHaveHappened呼叫ActionBlock<InterruptInfo>類型的虛擬。 zone.StartProgram明確地調用了zone.ZoneProgram.Start方法,但是這個調用並沒有被FakeItEasy看到。它返回以下錯誤消息:

Assertion failed for the following call: 
    ZoneLighting.ZoneProgramNS.ZoneProgram.Start(<NULL>, ActionBlock\`1 Id=1) 
Expected to find it exactly once but found it #0 times among the calls: 
    1: ZoneLighting.ZoneProgramNS.ZoneProgram.Start(inputStartingValues: Faked ZoneLighting.ZoneProgramNS.InputStartingValues, interruptQueue: ActionBlock`1 Id=2) 
    2: ZoneLighting.ZoneProgramNS.ZoneProgram.Start(inputStartingValues: <NULL>, interruptQueue: ActionBlock`1 Id=2) 

如可以從該錯誤消息中可以看出,在ActionBlocks的ID進行比較是不同的(1和2),這就是爲什麼它是無法看到該呼叫是製作。我的問題是,爲什麼啞鈴ActionBlock的ID = 1?我認爲是一個虛擬對象,它不應該有任何具體的細節,如ID等。這是因爲泛型不能被毀滅?

我在這裏看到類似的東西:https://github.com/FakeItEasy/FakeItEasy/issues/402

但我無法弄清楚,如果這是在談論同樣的事情或沒有。任何幫助將不勝感激。

回答

3

我不熟悉ActionBlock s,所以我不確定他們從Id得到的值,但我想我可以在你的測試中發現一些事情。

首先,我認爲你對Dummy是什麼感到困惑。如果是這樣,不要感覺不好。他們可能有點混亂。從Dummy documentation,一個假人

假人是一個對象時,需要某種類型的對象,FakeItEasy可以提供,但對象的實際行爲並不重要。

他們大多被FakeItEasy本身時,它需要創建一個對象來養活類的構造函數(我們將看到更多關於這個版本),或者當它需要從方法返回一個非fakeable對象或財產。終端用戶很少需要創建它們。

虛擬是一個實際的對象(它必須是 - 否則,我們怎麼能用它做任何事情?)。它必須有任何具體的細節,它的類型(在這種情況下,ActionBlock<InterruptInfo>)。對Dummying泛型類型沒有限制。在文檔的how a Dummy is made

來看,我們可以看到,自ActionBlock<InterruptInfo>可能不具有自定義IDummyDefinition可用(你有嗎?),並且它不是一個任務,這不是fakeable(因爲類是密封),然後通過調用其中一個ActionBlock constructors來製作虛擬人物,並使用虛擬人物來驗證每個參數。

我猜ActionBlocks有ID。他們如何分配,我不知道,但如果他們是一個很好的ID,那麼它看起來像我們有兩個不同的ActionBlock<InterruptInfo> s:一個在zone.StartProgram提供,並在測試中製作虛擬。

ActionBlocks文檔建議它不會覆蓋Equals,因此將執行參考比較,並且兩個ActionBlock(虛擬文件和生產代碼中使用的虛擬文件夾)不匹配。這就是爲什麼FakeItEasy無法識別該呼叫。

如果你只是想看看是否到zone.ZoneProgram.Start任何呼叫的第一個參數null,第二個參數一些ActionBlock做,我想你可能已經打算使用:

A.CallTo(() => zone.ZoneProgram.Start(null, A<ActionBlock<InterruptInfo>>.Ignored)) 
      .MustHaveHappened(Repeated.Exactly.Once); 

Ignored能也縮短爲_瞭解更多關於ignoring argument values,如果你願意)

這可能讓你過去你眼前的問題,雖然我有兩件事情的關注:。

  1. 它看起來像zone.ZoneProgram.Start被稱爲兩次,而不是「Exactly.Once」,但我敢肯定,你就可以解決這個問題,並
  2. 一般情況下,僞造被檢測物被認爲是一種反模式。通常情況下,供應商將僞造依賴項提供給正在測試的生產代碼。我並不是說它不起作用,但有時它會導致混亂。儘管如此,在當前問題得到解決之後,這可能是另一天的問題。

我希望能有所幫助。

哦,並且您問到了問題402.該問題是關於在定義將控制如何創建假人的定製類時給用戶更多的權力。除非您已經延長了IDummyDefinitionDummyDefinition的課程,否則這可能與此無關。

+0

感謝您的詳細回覆。我不知道密封的課程不能像這樣被弄糊塗。所以我的後續問題是:從測試角度來看,如何知道是使用虛擬還是使用.Ignored技術?在這兩種情況下,都需要該類型,但對象的實際行爲並不重要(從您的回覆中引用Dummy文檔)。 – Anshul

+0

至於你關於僞造被測試物體是反模式的觀點,爲什麼會這樣?如果我們只是測試對象的「管道」以確保應該連接的部件按照方法調用連接,那該怎麼辦?如何在不僞造對象的情況下進行測試? – Anshul

+0

傳遞給調用的參數無關緊要時使用「忽略」。一般來說,對於調用匹配語義,[Argument Constraints](https://github.com/FakeItEasy/FakeItEasy/wiki/Argument-Constraints)技術是可以使用的。 Dummy構造完成後,就像其他任何對象一樣,因此在'A.CallTo'中提供它就意味着它將與使用Equals的實際參數進行比較。如果你想比較說「真」,那麼你會關心答案,所以虛擬是一個不好的選擇。即使碰巧有效,也不清楚爲什麼。 –

相關問題