Search code examples
asp.net-mvcunit-testingintegration-testingmvccontrib-testhelper

ASP.NET MVC 2: What to test in views and controllers


I'm using MVC 2 with MVC contrib and Rhino mocks.

I am in need of help. It has been a painful weekend. I have been trying to look for good articles on how to do testing on controllers using MVC contrib. And no one has any decent answers for me. I want to know what do I need to test on a view and in controllers? Is this unit testing or integration testing?

Let me describe my basic scenario: I have an Index view that has a grid on it. In this grid I have a list of news items. In this grid, in the last column of every row, is an Edit link that takes the user to the EditNews view to edit the selected news item. Also on this Index view is an Add News button that takes the user to the CreateNews view.

Now given the current scenario, what tests do I need to write? Could you guys please also indicate if they are unit tests or integration tests. Do I need to write a test for the Edit link? Do I need to write a test for the Add News button? Do I need to write a test to check if the user is allowed on this Index page? This is what I currently have:

[Test]
public void Index_Should_Redirect_To_Error_View_When_User_Does_Not_Have_Permission()
{
}

[Test]
public void Index_Should_Log_Exception_When_User_Does_Not_Have_Permission()
{
}

[Test]
public void Index_Should_Return_Default_View()
{
   // Act
   var result = newsController.Index();

   // Assert
   result
      .AssertViewRendered()
      .ForView("Index");
}

UPDATED: Here is my Index action method:

public ActionResult Index()
{
   IEnumerable<News> news = newsRepository.FindAll();
   return View(news);
}

Any decent articles or sample code would be appreciated. Also on MVC contrib, the code samples aren't of much use. I would like to hear as much opinions as possible.

Thanks.


Solution

  • You need to make the distinction between unit tests, integration tests and web tests. Unit tests are for testing different components of your code such as controller actions in isolation. Integration tests are for testing the integration between your code and external components such as a repository which reads and writes data from a database and a web test is for testing an entire user scenario of your application such as the user typing some address in the address bar of his browser, clicking on some button, ...

    MVCContrib.TestHelper and Rhino Mocks are intended to simplify your unit tests. So in your scenario you should test your Index controller action. Without showing the code this controller action contains it is difficult to say what exactly do you need to test. In general what you could unit test in a controller action is that it validates the input, calls the proper methods on the repository and according to the results it returns the proper view.

    So let's suppose that you have the following Index action you are willing to test:

    public class HomeController: Controller
    {
        private readony INewRepository _repository;
        public HomeController(INewRepository repository)
        {
            _repository = repository;
        }
    
        public ActionResult Index()
        {
            var news = _repository.GetNews();
            return View(news);
        }
    }
    

    And the corresponding unit test:

    [TestClass]
    public class HomeControllerTests : TestControllerBuilder
    {
        private HomeController _sut;
        private INewsRepository _repositoryStub;
    
        [TestInitialize()]
        public void MyTestInitialize() 
        {
            _repositoryStub = MockRepository.GenerateStub<INewsRepository>();
            _sut = new UsersController(_repositoryStub);
            InitializeController(_sut);
        }
    
        [TestMethod]
        public void UsersController_Index_Should_Fetch_News_From_Repository()
        {
            // arrange
            var news = new News[0];
            _repositoryStub.Stub(x => x.GetNews()).Return(news);
    
            // act
            var actual = _sut.Index();
    
            // assert
            actual
                .AssertViewRendered()
                .WithViewData<News[]>()
                .ShouldBe(news);
        }
    }
    

    As far as your views are concerned you will need to write web tests to verify that they behave as expected. There are different tools that might help you here such as Selenium or directly use Web Tests if you have the Ultimate version of Visual Studio. Steven Sanderson also proposed an interesting approach for testing views you might take a look at.