Unit test to check if an action method called the service layer
I have a controller called NewsController, the constructor of this controller receives an INewsService as parameter.
I have a method in this controller called GetAllNews() that returns a JSON result that I use to populate a YUI datatable. I want to write a unit test that checks if the news service's FindAll method was called to return all the news items. How would I do this? What I currently have is:
public JsonResult GetAllNews()
{
var items = newsService.FindAll();
var jso开发者_高级运维nResult = Json(items);
return jsonResult;
}
My unit test for the controller looks like:
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();
}
The test passes with the above code. But if I were to change GetAllNews() to look like below then it also passes. Shouldn't it fail? What I am trying to test is if GetAllNews() uses the news service:
public JsonResult GetAllNews()
{
return null;
}
If you can get away with it, don't unit test that a particular method was called. The point of unit testing is to test behavior, not implementation. Testing that FindAll
is called is testing an implementation. This leads to brittle tests that break if you change the implementation but the behavior doesn't change. Clients don't care how you get them all the news, they just want you get them all of the news.
So
public void GetAllNews_should_use_news_service()
should be
public void GetAllNews_should_get_all_the_news
and I'll leave the details of coding that up to you.
As others have pointed out, testing for particular method calls can be brittle in the long run.
However, from a Rhino.Mocks standpoint, if you want to check expectations, you should be using a Mock instead of a Stub. Change you GenerateStub
to a GenerateMock
and your .Stub()
call to an .Expect()
call. That should fix your test.
You might find this article by Martin Fowler interesting on the differences between mocks and stubs.
http://www.martinfowler.com/articles/mocksArentStubs.html
Fowler points out stubs are used for state verification while mocks are used for behavior verification.
精彩评论