单元测试检查一个动作方法是否称为服务层

时间:2010-12-13 13:54:41

标签: c# asp.net-mvc unit-testing nunit

我有一个叫做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;
}

3 个答案:

答案 0 :(得分:3)

如果你能逃脱它,不要单元测试是否调用了特定的方法。单元测试的重点是测试行为,而不是实现。测试FindAll的测试是测试实现。如果您更改实现但行为没有改变,这会导致脆弱的测试中断。客户并不关心你如何获得所有新闻,他们只是希望你得到所有新闻。

所以

public void GetAllNews_should_use_news_service()

应该是

public void GetAllNews_should_get_all_the_news

我会留下编码的详细信息。

答案 1 :(得分:1)

正如其他人所指出的,从长远来看,对特定方法调用的测试可能会很脆弱。

然而,从Rhino.Mocks的角度来看,如果你想检查期望,你应该使用Mock而不是Stub。将您GenerateStub更改为GenerateMock,将.Stub()来电更改为.Expect()来电。那应该可以解决你的考试。

答案 2 :(得分:1)

你可能会发现Martin Fowler的这篇文章对于模拟和存根之间的差异感兴趣。

http://www.martinfowler.com/articles/mocksArentStubs.html

Fowler指出存根用于状态验证,而模拟用于行为验证