2010-12-13 12 views
0

我有一個名爲NewsController的控制器,這個控制器的構造函數接收一個INewsService作爲參數。單元測試檢查一個叫做服務層的動作方法

我在這個控制器中有一個名爲GetAllNews()的方法,它返回一個JSON結果,我用它來填充一個YUI數據表。我想編寫一個單元測試,檢查新聞服務的FindAll方法是否被調用以返回所有新聞項目。我將如何做到這一點?我目前擁有的是:

public JsonResult GetAllNews() 
{ 
    var items = newsService.FindAll(); 
    var jsonResult = Json(items); 

    return jsonResult; 
} 

的控制我的單元測試是這樣的:

public NewsControllerTest() 
{ 
    newsServiceStub = MockRepository.GenerateStub<INewsService>(); 
    newsController = new NewsController(newsServiceStub); 
} 

[Test] 
public void GetAllNews_should_use_news_service() 
{ 
    // Arrange 
    List<News> newsList = new List<News>(); 
    newsServiceStub.Stub(s => s.FindAll()).Return(newsList); 

    // Act 
    var actual = newsController.GetAllNews(); 

    // Assert 
    newsServiceStub.VerifyAllExpectations(); 
} 

測試與上面的代碼通過。但是,如果我改變GetAllNews()看起來像下面那麼它也通過。它不應該失敗嗎?我試圖測試是,如果GetAllNews()使用消息服務:

public JsonResult GetAllNews() 
{ 
    return null; 
} 
+0

作爲一個附註,爲什麼你認爲這是一個有用的測試? – bzlm 2010-12-13 13:56:46

+0

@bzim:我是初學者,還在學習。我並不總是清楚要測試什麼和不該做什麼。 – 2010-12-13 13:58:16

回答

3

如果你能擺脫它,不要單元測試一個特定的方法被調用。單元測試的重點是測試行爲,而不是實現。測試FindAll被稱爲測試實現。這會導致脆弱的測試,如果您更改實現但會破壞行爲不變。客戶不關心你如何得到他們所有的消息,他們只是想讓你得到他們所有的消息。

所以

public void GetAllNews_should_use_news_service() 

應該

public void GetAllNews_should_get_all_the_news 

,我就不打擾編碼是給你的細節。

+0

你的意思是?我的GetAllNews()方法中會出現什麼行爲?如果您命名測試GetAllNews_should_get_all_the_news,您會在測試代碼中包含什麼內容?您能否在上面的回答中提供一些示例代碼? – 2010-12-14 05:43:06

1

正如其他人所指出的那樣,從長遠來看,特定方法調用的測試可能很脆弱。

但是,從Rhino.Mocks的角度來看,如果你想檢查期望值,你應該使用模擬而不是存根。將您的GenerateStub更改爲GenerateMock,並將您的.Stub()呼叫轉至.Expect()呼叫。這應該解決你的測試問題。

+0

mock和stub有什麼區別?我什麼時候使用這兩種? – 2010-12-14 05:43:42

+0

存根用於提供罐裝響應。嘲笑是用來驗證期望。您可以使用模擬來提供預設的響應,但存根不會跟蹤方法調用,因此不能用於驗證期望值。 – PatrickSteele 2010-12-14 05:47:08