skip to content
Linkedin Twitter feed logo
16 June 2013

You should unit test your controller, NOT!

Unit Testing MVC

Unit testing per se is a controversial topic, what you should unit test is another controversial topic. The topic of this post started by a short conversation during a .NET London Group meeting back in 2010, I thought about it and then gave it more thoughts, I started using it in my projects, then now I have enough confidence to share my thoughts. Here is my opinion, if you agree or disagree, then please do comment.

Controllers should be slim

You’ve heard this before: “Controllers shouldn’t be fat, controllers should contain minimal code”, it’s a mantra.

The S in SOLID stands for SRP. A controller should have one role, it is the communication layer between a model and a view. Even with this role, it is violating SRP, one could say maybe we need two classes to take the role of a controller or a controller per action method, but let’s not delve into that.

The controller, by role, is overloaded with responsibilities, adding more responsibilities to it is a design crime (maybe one should be penalised by losing some StackOverflow or CodeProject points :) ).

Why do controllers get fat?

I did blog earlier on how views become fat Three Steps to Get Fat-Razor MVC Views on Diet, some points are common and some are specific to controllers:

Explicit validation of data in the action method

Validation of your viewmodel data in your controller violates two principles:

  1. SRP Design Principle: You are attaching more responsibilities to the controller.
  2. Encapsulation OOP Principle: You will have to expose your data outside your viewmodel to allow another object, the controller, to validate it, while the object itself should be responsible for its own data.

ASP.NET MVC 4 has a good validation ecosystem that will help you moving your validation code to where it belongs.

Mapping a model to a viewmodel

The mapping from a model to a viewmodel should not be done in the action method. My favourite solution is to use a CQRS type query pattern so I don’t have to do this boilerplate anywhere. Here is a good Introduction to CQRS.

Leaking some business logic

This is not a place for any business logic. The controller should be calling a service, of a classical DDD implementation, or issuing a query or a command of CQRS.

Http-related code in the action method

Having a special HTTP case that requires special handling should not be done here. Action filters might be the answer.

What are you unit testing?!

Given the above and if your action methods have almost no code, then what are you unit testing? Do you want to test if you are returning the proper view or do you want to test if you have decorated your action method with the proper attributes? I wouldn’t, I usually have a deadline to hit and I am against boilerplate code.

If someone tells me their controller requires unit testing, I will ask, did you design your controller properly?

Conclusion

Unit testing is a mean for providing higher quality software and not an aim per se. Having too many redundant unit tests will cause a future maintenance headache and will cost more project development time.

If an area/layer requires unit testing then you should probably test it, but for other areas more tests may be less quality.

Update – I told you not to unit test your controllers, by keeping them empty, here is one way to keep your controllers thin: Implementing a CQRS-based Architecture with MVC and Document DB.

7Comments
leave your own
  • Óscar Sotorrío October 29th, 2013

    Hi Adam,

    I have to admit that it is an interesting point of view. But I still wonder about something.

    You have talked about unit test in general terms but you haven’t commented if tests are verified as state or behavior.

    Could be interesting to test if the controller makes a specific call?. What do you think about that?. In your opinion, should we verify behavior controller?

    Thanks

  • Chris Emerson November 19th, 2013

    “A controller should have one role, it is the communication layer between a model and a view. ”

    Can’t agree with this – the controller should instantiate both the view and any models needed depending on the route / input parameters, but the views should then access the models directly and handle and communication between them. The controller shouldn’t be a ‘mediator’ that separates them – MVC says that the view should take what it needs from the models and display it. In a web application this is a one time thing, but in a desktop/stateful application the view is updating all the time based on changes notified from the models.

  • Dheeraj November 22nd, 2013

    I agree with you their is no need to do unit testing for controller but what about Model.

    If it is require to do unit testing for Model then can share with me any examples

    thx

  • Dan pupek February 6th, 2014

    I have to disagree. I do agree with chris. The controller is more than just a middle man. You should have business logic in their.

  • Suresh.C February 18th, 2014

    One of the core objective of MVC pattern is enabling testablity on the presentation layer, especially verigy the logic in controller. What else?

  • Rick August 28th, 2014

    The controllers should never have business logic in them. You should have a service layer for that and then unit test that service layer. The biggest controller I have is probably 7 lines and exists to do minimal clue code between the service and view.

    Why you may ask have a service layer doing the business logic vs the controller? Because that business logic may need to be exposed in different applications and having it in it’s own service layer (which for me is it’s own DLL project) you can move it around and reuse it. Controllers can’t be moved around to another project or easily have them wrapped into a web api. You never know what functionality will be required by different applications and by having your own service layer, you’ll be able to reuse them very easily.

  • Johnf670 September 6th, 2014

    I discovered your blog web site website on the search engines and check several of your early posts. Always sustain up the very excellent operate. I lately additional increase Rss to my MSN News Reader. Looking for toward reading much far more on your part later on! kdgeagfdceaa

Leave a Reply

Gravatar