Thoughts on Unit Testing in Asp.NET MVC

Arnt Berge 
5. april 2011

I have been working with TDD and Mvc in different flavors for 10 years now. The last 2 years I have been working with Asp.Net Mvc. I have written down some thoughts on unit testing in an Mvc app with principles that I have come to value. These principles help me write good maintainable tests. Much of it also applies to unit testing in general.

Unit Testing in General

When writing tests it is important to think about responsibilities. Tests should also follow the principles of DRY(Do not Repeat yourself). You should only test the things an object is responsible for. If you test more you will duplicate tests. This results in fragile tests that require a lot of attention to keep the build green. Test object behavior not functions. Do not test functionality of other objects. That should be done in separate test classes for the external objects. You can and will have to use other objects in test cases, but bear in mind the responsibility of the object at hand.

Over view of what to test

View: Ideally you should test java scripts and rendered views. For view tests test for what is the views responsibility. The views responsibility is layout and presentation. Test that data is updated in the correct place and that the view is rendered in a certain way given a specific model. Only test the rendering logic. For Ajax functionality e.g. test that the UpdateTargetId is changed. Do not test the values. What values are set should be a model or business logic responsibility. If you have to test the values your view is probably doing too much. Consider separate view models to ease unit testing of view logic.

Controller: The controller is responsible for delegating actions and events from view to model. As a rule of thumb we can say that you should only test that the controller returns the correct view and model. If you need to test any ting else your controllers are probably doing to much. Consider to move responsibilities out of the controller to other objects.

Business Logic and model: Test the responsibility of the objects. Her you test calculated values and results of business rules. Decouple your logic from external resources. It is hard to test if your model is tightly bound to a database or SharePoint. Configuring a model for testing in code should be easy. If it’s hard and requires a lot of code consider refactoring.

Data access layer/ integration layer: Consider integration tests. It is hard to write unit tests at this level. Mocking often results in testing that your code is written according to your assumptions. If your assumptions are wrong your code will still pass.