2015-09-20 41 views
0

我對單元測試非常熟悉,並且瞭解模擬和存根之間的區別。 Roy Osherove最簡單的解釋是,所有的假貨都是以存根的形式出現,直到你對他們斷言,然後他們是嘲弄。使用單個假作爲模擬和存根

同樣,我明白了。我的問題是「這是錯誤的使用一個假的情況下同時作爲模擬和存根?就拿從犀牛嘲笑文檔下面的例子(http://ayende.com/wiki/Rhino+Mocks+3.5.ashx

public void When_user_forgot_password_should_save_user() 
{ 
    var mockUserRepository = MockRepository.GenerateMock<IUserRepository>(); 
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>(); 

    var theUser = new User{HashedPassword = "this is not hashed password"};  

    mockUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser); 

    mockUserRepository.Expect(x => x.Save(theUser)); 

    var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender); 

    controllerUnderTest.ForgotMyPassword("ayende"); 

    mockUserRepository.VerifyAllExpectations(); 
} 

你會發現mockUserRepository進行命名mock這個詞,並且正在調用GenerateMock工廠,因爲進一步在代碼中mockUserRepository具有爲其建立的行爲期望,並且最終期望行爲正在被驗證。很好,但是沿着mockUserRepository調用它的Stub()方法「可以」通過調用GetUserByName()返回的數據在同一個對象上

顯然,這個例子顯示了使用明確的na醫學和宣稱模擬既是一個模擬和存根。回到Roy Osherove的定義,即所有的假貨都是存根,直到你對他們斷言,我不得不相信,使用假貨作爲模擬和存根(雖然當然有效)是不好的做法。

有沒有人知道這樣做是否有判決?

回答

0

我真的,真的不遵循你的邏輯。如果每個模擬都是一個存根,並且您同意這一點,那麼如何將單個實例用作模擬和存根是錯誤的。你沒有選擇:模擬是一個存根。每當你用它作爲模擬時,你也可以用它作爲存根。爲了能夠驗證模擬已被調用,模擬必須被調用。如果它已被調用,它在調用時必須做某事(即返回一個特定的拋出異常值)。爲了能夠讓它返回一些東西,你必須把它捅死。

順便說一句,大多數情況下,被測組件使用給定協作者的一個實例,而不是兩個。顯然,你需要存根那個實例。爲了驗證這個實例的交互,這個存根必須成爲一個模擬。所以你必須使用它作爲模擬和存根。

+0

我不同意每個模擬都是一個存根,也不是我說的。我說每一個「假」都是作爲一個存根開始的,根據你的使用方式,它可能會變成一個模擬。 這僅僅意味着我們需要爲2個可能的原因創建一個假對象(假的輸入到被測試的方法或假的與外部系統的交互),但除非我們堅持反對假冒,假冒屬於類別的一個存根。如果你堅持反對它,唯一一次你的假可以準確地稱爲模擬。 – user1739635

+0

這不是主要觀點。假設一些代碼不會'int i = foo.getValue(); foo.setValue(i * 2);'。如果你想測試這個方法,你需要存儲foo,以便getValue()返回一個整數,例如5。爲了確保它使用10調用foo.setValue(),就像它應該做的那樣,你需要驗證foo.setValue()已經被調用了10,從而使用stub作爲模擬。你沒有選擇。該代碼不使用2個不同的foos。它只使用一個。所以,存根也需要是一個模擬。 –

+0

是的,但這些將是兩個不同的測試,因此在一個測試中,我需要存根foo.getValue(),以便它將返回我的方法在測試期望的罐頭數據,並且我將對我的方法測試。而且,在另一個測試中,我需要模擬foo.setValue()並聲明它被調用。不應該有一個測試來處理這兩種情況。 – user1739635

相關問題