2011-04-20 57 views
3

有時我覺得嘲笑受試者本身的願望,我知道它看起來很奇怪。嘲笑SUT本身

這裏是例子。我使用C#,但沒關係。想象一下你有一個班級管理一些收藏。它有方法

public void Insert(int position, T element) 

public void Delete(int position) 

這些方法的邏輯是不是很簡單。除了修改集合外,他們還可以舉例說明事件,訂閱/取消訂閱事件,獲取/釋放資源或執行計算。這些方法用單元測試來檢查這個功能。

現在你添加一個方法

public void Replace(int position, T element) 
{ 
    Delete(position); 
    Insert(position, element); 
} 

我不能完全肯定,但對我來說,這是不值得再次測試所有這些事情,這種方法。相反,檢查這個方法是否真正調用了兩個是有意義的。

如果前兩個方法屬於另一個類或接口,那麼使用現代模擬框架將很容易。但是這些方法屬於SUT。

是否有可能做我想要的東西?如果不是,那爲什麼?這是嘲諷方法的一個無意的缺陷還是設計。如果第一,是否有解決方法?如果第二,我應該如何設計和測試描述的程序?

回答

1

首先,是的,至少在FakeItEasy中是可以做到的。

其次,這可能不是一個好主意。我說可能是因爲有些情況下,至少不是一個非常糟糕的主意。在上面的例子中,我會說這可能是一個壞主意,但我不確定這是一個真實世界的例子。這是一個壞主意,因爲替換方法可能只是您的類的擴展方法,並且這樣它將很容易測試。

但是,如果你決定了你的情況是個好主意,這是你會怎麼做,在FakeItEasy(確保你要斷言的方法是虛擬的):

// In your set up 
var sut = A.Fake<MySut>(); 
A.CallTo(sut).CallsBaseMethod(); 

// In your test of the Replace-method 
A.CallTo(() => sut.Delete(thePosition)).MustHaveHappened(); 

我我不確定在其他嘲諷的框架中很容易做到這一點,但這可能會指出你在正確的方向。

正如我所說,在大多數情況下這可能不是一個好主意,但我自己也使用了這種技術,它可能會有用。

+0

太好了,謝謝!我不使用FakeItEasy,但會在我目前使用的框架中尋找類似的功能,並記住使用FakeItEasy作爲備用選項。是的,這只是一個例子。在實踐中,我經常遇到有些方法,通常是私有的,在同一個類中被其他方法廣泛使用。 – 2011-04-20 11:57:18

+0

@PatrikHägne:謝謝,但是我怎樣才能測試那個叫做 靜態擴展方法的類呢? – Mohsen 2017-07-10 07:07:43

3

我不確定你使用的是什麼框架,但是我可以在Rhino.Mocks中做到這一點。我沒有實例化SUT,而是創建了它的一個存根(請注意,我不是創建接口的存根,而是創建對象本身)。存根仍然會運行SUT的代碼,但也會跟蹤我的呼叫。

//Create a stub of my SUT, passing the constructor arguments to GenerateStub() 
_sut = MockRepository.GenerateStub<SutClass>(_mockedDependency); 

這讓我斷言之類的東西......

_sut.AssertWasCalled(x => x.DoTheStuff(_argObject1, _argObject2), 
        o => o.Repeat.Once()); 

非常漂亮。現在我只是需要確保我不要濫用它;)

編輯: 我要補充一點,以測試方法DoTheStuff被調用時,它看起來像它可能需要overridablevirtual在C# )。我認爲這不是必要的,但是我前幾天寫的一個測試表明情況正好相反。讓我知道如果我錯了。

+0

哦,太棒了!謝謝。無法將兩個答案標記爲已選中,因此只提高了 – 2012-05-01 19:10:20

+0

沒問題,謝謝!只是想把它放在那裏,以備將來的答案 - 可能希望在Rhino Mocks中做到這一點的尋求者。 – 2012-05-01 22:31:38

+0

適用於使用MOQ的虛擬成員,既適用於.Setup()也適用於.Verify()。這感覺應該是一個非首選的做法,因爲它可能導致混亂的難以閱讀的測試,但我仍然會用它捏。 – 2013-06-27 16:54:36