2010-12-13 52 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