Controller instantiation testing

As I just mentioned in my post on Robust testing the best kind of test is one that automatically updates when you change your code. In particular when that test provides you a lot of value and checks something that would otherwise have a likelihood of going wrong when you deploy it (in particular production!). This post gives an example of this kind of test.

The problem

One thing that I’ve come across a number of times is a situation where controllers aren’t able to be instantiated because one of the constructor parameters isn’t able to be resolved from the dependency injection container. This is a pain and causes an ugly yellow screen of death to show up for requests to the affected controller(s) (or a nice error page if the environment you deploy to has that set up).

Ideally you should check the pages that a controller serves up after adding new parameters to it’s constructor before pushing your code changes, but sometimes you might forget and your development environment will break (I’m making a few assumptions here: continuous integration and continuous deployment to a dev environment after your tests pass). While it’s both quick and easy to identify and resolve this problem it’s annoying and can be disruptive to any testing on that environment. Ideally, the problem should be picked up much sooner than after the deployment.

Also, you may make some sort of changes that have unintended consequences like, say, changing the namespace of some classes that are registered by namespace to your dependency injection container.

In these situations, it’s impossible to use the compiler to check that the dependency resolution will work because they are resolved at run time. However, we can do the next best thing and write a test that will break!

An example solution for ASP.NET MVC

Consider the following code (this example in NUnit, but the same concept applies for other libraries):

namespace MyApp.Tests.Controllers
{
    [TestFixture]
    class ControllersShould
    {
        private IContainer _container;

        [TestFixtureSetUp]
        public void FixtureSetup()
        {
            _container = MvcApplication.RegisterDependencies();
        }

        // ReSharper disable UnusedMember.Global
        public IEnumerable<Type> GetAllControllers()
        {
            return typeof(MvcApplication).Assembly.GetTypes().Where(t => t.IsAssignableTo<ControllerBase>() && !t.IsAbstract);
        }
        // ReSharper restore UnusedMember.Global

        [Test]
        [TestCaseSource("GetAllControllers")]
        public void Instantiate(Type controller)
        {
            _container.Resolve(controller);
        }
    }
}

This test uses the (really handy) [TestCaseSource] attribute so each controller that is instantiated is presented as a separate test. This makes sense semantically and allows you to see all of the controllers that can’t be instantiated, rather than it short-circuiting at the first one that doesn’t. In saying that, if your unit testing library doesn’t support that kind of testing metadata then the same thing can be implemented as a loop inside the test.

The real magic here is in the GetAllControllers() method, which uses reflection to scan the assembly of the web application to find all classes that extend ControllerBase. You could use Controller too, but if for example you are using ActionMailer.Net then your mail controller will inherit from MailerBase, which extends ControllerBase. It also ensures the classes returned aren’t abstract.

Once you have this list of types, resolving each of them with the dependency injection container (in my case Autofac, but as with the unit testing library, this technique applies generically) you are using is easy. The only requirement is you make the method with all of your dependency registrations public and static so it’s available to call within the test. I usually have a method called RegisterDependencies() on the application class (unless the dependencies are shared with non-web projects too).

The beautiful thing about this test is that as soon as you add new controllers it will automatically apply the test to that controller! So you can literally write the test once and then forget about it :).

Note: there are a few implications of this technique that you should consider before using it:

  • This will call the constructor of all your controllers; if any of them are doing anything “funky” in their constructors then this might not be desirable. Personally, all my controller constructors ever have are storing the dependencies in the private instance scope.
  • More importantly, all of the dependencies that the controllers have and indeed all the dependencies down the chain will have their constructors called as well. This might well be a problem for your application depending on what it does so you should be very conscious of this. This usually involves me needing to set certain connection strings in the App.config of the test to test datasources etc. so the constructors don’t throw exceptions.
  • All of the dependencies to the controllers need to be such that your dependency container, with all the registrations made in your RegisterDependencies() (or similar) method, can resolve them. If you have any custom controller registration code outside of what your dependency injection framework provides you might need to adjust the approach above accordingly.
  • This is (at least in the way it’s written above, it could be adjusted though) an all-or-nothing approach – it will resolve all of the controllers.
  • If your controllers are in multiple assemblies then the GetAllControllers() method will need to be adjusted to scan the other assemblies.

Other applications

There is another application of this particular style of test that I have used before and is worth mentioning. If you are in a situation where most (or all) of your controllers must inherit from a base controller that contains important/shared functionality for your website then there is no way for you to use the compiler to check that the classes inherit that base controller. You will only find out if a new controller has that inheritance missing when loading up the site and even then, depending on the nature of the functionality, maybe only in certain circumstances (so it mightn’t be immediately obvious). As before, you can write a test that will automatically check this for you as soon as you add any new controllers.

Following is an example of such a test that I have used before:

        // ReSharper disable UnusedMember.Global
        public IEnumerable<Type> GetAllHttpControllers()
        {
            return typeof(MvcApplication).Assembly.GetTypes().Where(t => t.IsAssignableTo<Controller>() && !t.IsAbstract && t != typeof(ErrorController));
        }
        // ReSharper restore UnusedMember.Global

        [Test]
        [TestCaseSource("GetAllHttpControllers")]
        public void Inherit_from_base_controller(Type controller)
        {
            Assert.That(controller.IsAssignableTo<BaseController>());
        }

In this case the base controller class is called BaseController. There are a couple of differences to note here: I am checking for controllers that inherit from Controller rather than ControllerBase because I only want the controllers that are serving HTTP requests and I actually have an exclusion here for one particular controller, the ErrorController, because I didn’t want that particular one to extend BaseController.

7 Replies to “Controller instantiation testing”

  1. It’s a good test.

    But not for that reason.

    This is an integration test. It’s focus is on your application, not the individual controllers.

    At each level of your application (i.e. components at an individual basis, components used together, end to end, etc) tests should be explicit rather than programmatically determined.

    Otherwise, what’s testing the tests? (in terms of explicit tests, it’s the human at the time of writing/changing that test)

    The child components to the thing you are testing can be tested dynamically (using mocks, reflection) because those child components have their own separate explicit tests.

    Also, having constantly changing tests can also be a sign of bad API (as well as a sign of bad testing).

    Which is very useful once you start to consider tests as more than just validation, but also as a way of making your software tangible.

    Note that I do say this coming from my background of dynamically typed languages :p

    1. To be honest with you Steve, I’ve always felt uncomfortable about people getting really picky about whether a test is a unit test, or an integration test or a … I don’t think it’s productive. Don’t get me wrong, if you are doing tests on a single module/class then I think you should consistently mock all or none of the dependencies (otherwise it will be a mess and you will have no idea what you are and aren’t testing).

      But, for instance I will always test my data repositories with actual round trips to the database because there is no point in mocking out the database – it doesn’t give you any value. I will also combine these integration/unit (integration with the database, but testing a single unit – an individual repository method) tests with my “unit tests” project because they don’t take a huge amount of time to execute.

      I know a lot of people will say you should separate integration from unit tests, but I don’t think that makes sense unless the integration tests take a long time to execute. This is why I don’t like people being really particular in identifying what type of test something is – it doesn’t mean anything valuable!

      Re: explicit tests I agree that if your implementation is “magic” in that it uses meta programming or other terse language features that the test should have a different more explicit implementation (e.g. passing all the different test cases to a unit test method) in order to give a good value test. But, if the implementation is explicit, as is the case in terms of specifying dependencies to a controller then I think it’s perfectly valid, and frankly a good idea (to save time and make your code more maintainable) to make the tests programmatic.

      In terms of what tests the tests I disagree with your assertion. In fact, it’s the code that tests the tests and vice versa. When a human writes the test they are merely specifying their intent on the code design, what actually tests the test is writing the code implementation that passes the test. If the programmer writes an implementation that is correct, but the test (incorrectly) fails then they will modify the test to correct it because the test was wrong. The same applies in reverse when changing the implementation to pass a failing test.

      Agreed re: bad API as well as bad tests.

      1. So when I said “integration test”, my intention was more to point out the focus of the test rather than this concept of only one thing vs many things in the one test.

        So it’s integration in that you’re testing the things are helping with the task the parent thing needs to do. Rather than testing those things in their own right.

        An idea that becomes important if you write everything as a thing providing functionality, rather than a thing solving a problem. (subtle difference).

        When I say humans test the tests, that also involves ensuring against false positives, which by their very nature can’t be seen by the computer.

        As for programmatic tests. My rant doesn’t cover the test in your blog post. That is a good test that makes sure that all your controllers instantiate. It’s likely controllers are added in the future and hence you want your test to keep up with that without the developer knowing that they need to edit the test.

        My problem with programmatic tests is where code paths inside the test itself is determined via complex rules.

  2. Thank you for your article! I’m learning testing of MVC applications and it helps me.
    With Autofac you can use IContainer.IsRegistered(Type) in place of your IContainer.Resolve(Type). The intention is more clear and it should not instantiate an object.
    In my application I use injection of external dependencies through action parameters. I’ve wrote a similar test for my case. You just need to get all action method infos and check through the container their types are registered. But you need to filter form’s parameters out. I do filtering by the parameter’s type full name (it should not start with ‘System’ and should not ends with ‘ViewModel’). For every application this filtering criteria can be unique.

    1. If you use IsRegistered won’t that just check that the controller is registered rather than all it’s dependencies and their dependencies etc. down the chain?

      Thanks for the comment! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *