@robdmoore

Blog about software engineering, web development, agile/lean/Continuous Delivery, C#, ASP.NET and Microsoft Azure.

Rob is the Chief Technology Officer of MakerX where he is building out a vision 6 years in the making, including the principles, culture, people, approaches, intellectual property and successful deliveries that form the basis of an amazing company. #makersmake

He is an Open Source Software contributor via his personal GitHub as well as TestStack and MRCollective.

He lives in Perth, Australia and has a BEng (Hons 1) (CompSysEng) and BSc (CompSc). You can find him on Twitter and GitHub as @robdmoore.

Robert is interested in agile methodologies, lean, continuous delivery, software engineering, web development, aircraft and floorball.

All source code on this blog and Robert’s Gists are Public Domain unless otherwise stated.

Posts - Page 17 of 22

Controller instantiation testing

  • 5 min read

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.

Read More

Robust testing

  • 2 min read

My favourite kind of test is one that automatically applies itself to any changes in your codebase. That way you write the test once and then you can forget about it because it will always give you the assurance that it is testing what you intended it to. Reflection can be really handy for this because it allows you to scan your assembly for classes that you want to apply your test to for instance. I will post a blog post momentarily with an example.

In instances where you can’t automatically apply the test I find it useful to put code in the test that will fail the test if your implementation changes. For example if you are testing the filters that are returned from a filter provider and you are checking for the two filters that you are expecting are provided then you might put in a further check to ensure that only 2 filters are provided so that the test fails if you add more filters. Adding more filters is probably the expected behaviour, but at least it forces you to stop and think about whether the new behaviour what you expect based on your expression of the design of the system (the tests). In the case of the filters, if you are say providing different filters depending on different conditions it’s certainly reasonable that an error could be introduced into the code resulting in incorrect filters being provided for some conditions that you want your test to catch.

In saying that, the danger that you may come across when you make your tests explicit is you may find yourself having to constantly make tedious updates to the tests for minor code changes that you often make. If you find yourself in this situation it’s important to reassess the test and either make it automatically apply based on your implementation, as mentioned above, or adjust the test to make it less restrictive or remove it completely (obviously you still want to have confidence in your codebase so you need to weigh up the tediousness of the test with the value of what is being tested). This is why controller testing is often not worth it (check out the controller testing library I have just released though, which goes some way towards addressing that).

At the end of the day, I think a pragmatic approach is required for writing tests and deciding what should and shouldn’t be tested and how strictly it should be tested based in balancing cost/maintainability of the testing against the value that the tests provide. If you can write tests that are flexible enough to automatically apply as you write new code then that is the best possible result!

Read More

FluentMVCTesting: Fluent, terse and maintainable ASP.NET MVC controller testing

  • 1 min read

I would like to announce the release of a software library I have been using for the last year or so as open source via NuGet / Github: FluentMVCTesting.

The motivation behind this library is to provide a way to test MVC actions quickly, tersely and maintainably. Most examples I find on MVC controller testing are incredibly verbose, repetitive and time-consuming to write and maintain.

Given how quickly you can write controller actions and how simple they are (assuming you are following best practices and keeping them lean) the time to test them generally isn’t worth it given you can glance at most of your controller actions and know they are right or wrong instantly.

This library aims to make the time to implement the tests inconsequential and then the value your tests are providing is worth it.

The other problem that I’ve noticed with most examples of controller testing is that there are a lot of magic strings being used to test view and action names; this library also aims to (where possible) utilise the type system to resolve a lot of those magic strings, thus ensuring your tests are more maintainable and require less re-work when you perform major refactoring of your code.

I came up with this library after using the MVCContrib.TestHelper library for quite a while, but becoming frustrated with it; the library was initially created during the experiment I conducted to try and create terse controller tests (which I still have to write a follow-up post for at some point!). I have been using the library for over a year on a number of projects both personally and professionally.

A small code snippet to whet your appetite (go to the NuGet site for more detailed documentation and examples):

// Check that a post to the Login action with model errors returns the Login view passing through the model
var vm = new LoginViewModel();
_controller.WithModelErrors().WithCallTo(c => c.Login(vm)).ShouldRenderDefaultView().WithModel(vm);
// Check that a post to the Login action without model errors redirects to the site homepage
_controller.WithCallTo(c => c.Login(new LoginViewModel())).ShouldRedirectTo<HomeController>(c => c.Index());

Enjoy!

Read More

Web Deploy Package Connection String Parameterisation Problem

  • 3 min read

I recently came across a problem using web deploy packages, and more specifically with connection string parameterisation. I was generating a web deploy package using the “Package” MSBuild command and then deploying to a remote server using MSDeploy. The problem I came across was that the parameterised connection strings weren’t being replaced.

That resulted in the deployed web.config file looking something like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  ...
  <connectionStrings>
      <add name="SomeConnectionString" connectionString="$(ReplacableToken_SomeConnectionString-Web.config Connection String_0)" />
  </connectionStrings>
  ...
</configuration>

I used a variety of approaches - DeployOnBuild MSBuild command, Visual Studio GUI interface, the generated .cmd file and direct msdeploy call - to deploy the package to check whether the problem was simply that I was somehow deploying it incorrectly, but they all resulted in the same problem.

Most of the Google results that came up simply said to turn off parameterisation, but in this instance I wanted to use parameterisation. While I was using XDT transformations, I also wanted to use connection string parameterisation so I could substitute the connection strings for entries in a password safe as part of an automated deployment step.

The build output wasn’t terribly helpful, so I passed the verbose option to msdeploy and got the following interesting output:

    ...
    [16:08:33][Step 2/2] Verbose: Parameter entry 'SomeConnectionString-Web.config Connection String/1' could not be applied anywhere.
    [16:08:33][Step 2/2] Verbose: The dependency check 'DependencyCheckInUse' found no issues.
    [16:08:33][Step 2/2] Verbose: The synchronization completed in 2 pass(es).
    [16:08:33][Step 2/2] Total changes: 10 (0 added, 0 deleted, 10 updated, 0 parameters changed, 1004778 bytes copied)
    [16:08:33][Step 2/2] Process exited with code 0

This didn’t really make a huge amount of sense and after some sanity checking to make sure parameterisation does actually work (created a new ASP.NET website and deployed it successfully) I started comparing all the differences in my .csproj configuration to a blank project. After some tedious trial and error I managed to narrow the errant configuration to the following (seemingly) innocuous line:

<BaseIntermediateOutputPath>$(ProjectDir)..obj</BaseIntermediateOutputPath>

You might be asking why I had that line in there in the first place? It is certainly a bit weird and you would normally expect it to be set to “obj”. In this case it was there so that when MvcBuildViews was next executed after building a package it didn’t choke with the following error (on the intermediate web.config files in the obj folder):

It is an error to use a section registered as allowDefinition=’MachineToApplication’ beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.

When I initially came across that problem I changed the location of the obj folder since it seemed the best option compared to the other options such as running clean before all builds or deleting the obj folder, both of which would slow down the build and be tedious and annoying. Also, I didn’t want to turn MvcBuildViews off since I want assurance on the build server that the views all compiled fine.

Since this was no longer an option (up until this point all web deploys were done manually so we hadn’t actually come across this new problem!) I came up with the following configuration as a solution (props to my Senior Dev, Matt Davies, for finding the relevant StackOverflow post for the inspiration):

  <Target Name="CleanPackage" BeforeTargets="MvcBuildViews" Condition="'$(MvcBuildViews)'=='true'">
    <CallTarget Targets="CleanWebsitesPackage" />
    <CallTarget Targets="CleanWebsitesPackageTempDir" />
    <CallTarget Targets="CleanWebsitesTransformParametersFiles" />
  </Target>
  <Target Name="MvcBuildViews" AfterTargets="Build" Condition="'$(MvcBuildViews)'=='true'">
    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
  </Target>

Basically, if you have MvcBuildViews set to true then it will run MvcBuildViews directly after the build and before running MvcBuildViews it will run the CleanWebsitesPackage, CleanWebsitesPackageTempDir and CleanWebsitesTransformParametersFiles targets which clean up the web deploy package files and thus the web.config files that mess with MvcBuildViews.

Update (17 Feb 2013)

If you are trying to use the above MSBuild with Visual Studio 2012 then it won’t work. I have blogged a solution that works in both Visual Studio 2012 and Visual Studio 2010 though.

Read More

Testing Url Helper within controllers in ASP.NET MVC

  • 2 min read

I recently had some code like the following in a controller that I wanted to test. The Facebook Connect API, despite being fairly awesome, is tied to the URL of the page so whenever you change the URL of your page then you will lose all your comments. This code was to get the initial URL of the page and store it in the database so that URL was used from then on:

var url = ControllerContext.RequestContext.HttpContext.Request.Url;
vm.FacebookCommentUrl = string.Format("https://{0}{1}", url.Authority, Url.Action("Detail", new { Id = "000", Controller = ArticleType.ToString() })).Replace("000", "{0}");

It’s easy to mock Request.Url within the ControllerContext; something like MVCContrib.TestHelper will mock it out for you with a few lines of code. Personally, I use the following code in conjunction with the AutoMock library to do it:

    public static class AutoMockContainer
    {
        public static AutoMock Create()
        {
            var autoMock = new AutoMock();
            var httpContext = Substitute.For<HttpContextBase>();
            autoMock.Provide(httpContext);
            var server = Substitute.For<HttpServerUtilityBase>();
            httpContext.Server.Returns(server);
            var request = Substitute.For<HttpRequestBase>();
            var parameters = new NameValueCollection();
            request.Params.Returns(parameters);
            var formParameters = new NameValueCollection();
            request.Form.Returns(formParameters);
            var qsParameters = new NameValueCollection();
            request.QueryString.Returns(qsParameters);
            var headers = new NameValueCollection();
            headers.Add("Host", "localhost");
            request.Headers.Returns(headers);
            request.AppRelativeCurrentExecutionFilePath.Returns("~/");
            request.ApplicationPath.Returns("/");
            request.Url.Returns(new Uri("http://localhost/"));
            request.Cookies.Returns(new HttpCookieCollection());
            request.ServerVariables.Returns(new NameValueCollection());
            autoMock.Provide(request);
            httpContext.Request.Returns(request);
            var response = Substitute.For<HttpResponseBase>();
            response.Cookies.Returns(new HttpCookieCollection());
            response.ApplyAppPathModifier(Arg.Any<string>()).Returns(a => a.Arg<string>());
            autoMock.Provide(response);
            httpContext.Response.Returns(response);
            var routeData = new RouteData();
            var requestContext = Substitute.For<RequestContext>();
            requestContext.RouteData = routeData;
            requestContext.HttpContext = httpContext;
            autoMock.Provide(requestContext);
            var actionExecutingContext = Substitute.For<ActionExecutingContext>();
            actionExecutingContext.HttpContext.Returns(httpContext);
            actionExecutingContext.RouteData.Returns(routeData);
            actionExecutingContext.RequestContext = requestContext;
            autoMock.Provide(actionExecutingContext);
            var actionExecutedContext = Substitute.For<ActionExecutedContext>();
            actionExecutedContext.HttpContext.Returns(httpContext);
            actionExecutedContext.RouteData.Returns(routeData);
            actionExecutedContext.RequestContext = requestContext;
            autoMock.Provide(actionExecutedContext);
            var controller = Substitute.For<ControllerBase>();
            autoMock.Provide(controller);
            actionExecutingContext.Controller.Returns(controller);
            var controllerContext = Substitute.For<ControllerContext>();
            controllerContext.HttpContext = httpContext;
            controllerContext.RouteData = routeData;
            controllerContext.RequestContext = requestContext;
            controllerContext.Controller = controller;
            autoMock.Provide(controllerContext);
            controller.ControllerContext = controllerContext;
            var iView = Substitute.For<IView>();
            autoMock.Provide(iView);
            var viewDataDictionary = new ViewDataDictionary();
            autoMock.Provide(viewDataDictionary);
            var iViewDataContainer = Substitute.For<IViewDataContainer>();
            iViewDataContainer.ViewData.Returns(viewDataDictionary);
            autoMock.Provide(iViewDataContainer);
            var textWriter = Substitute.For<TextWriter>();
            autoMock.Provide(textWriter);
            var viewContext = new ViewContext(controllerContext, iView, viewDataDictionary, new TempDataDictionary(), textWriter)
            {
                HttpContext = httpContext,
                RouteData = routeData,
                RequestContext = requestContext,
                Controller = controller
            };
            autoMock.Provide(viewContext);
            return autoMock;
        }
        public static T GetController<T>(this AutoMock autoMock) where T : Controller
        {
            var routes = new RouteCollection();
            MyApplication.RegisterRoutes(routes);
            var controller = autoMock.Resolve<T>();
            controller.ControllerContext = autoMock.Resolve<ControllerContext>();
            controller.Url = new UrlHelper(autoMock.Resolve<RequestContext>(), routes);
            return controller;
        }
    }

Above is the current version of the code that I use, but I change it every now and then when there is some other part of MVC that I need to mock, but haven’t yet. In this particular instance I was having trouble figuring out how to get Url.Action to return the actual URL - it was returning an empty string. I was registering my routes by calling the static method in my MvcApplication class, but that wasn’t enough. It took some Googling and perseverance to finally find the right set of steps to get it working (the one that really threw me was having to mock ApplyAppPathModifier in the Response object!):

  1. Register your routes in the route table
  2. Mock Request.Url (new Uri(“http://someurl/”))
  3. Mock Request.AppRelativeCurrentExecutionFilePath (“~/”)
  4. Mock Request.ApplicationPath (“/”)
  5. Mock Request.ServerVariables (new NameValueCollection())
  6. Mock Response.ApplyAppPathModifier(…) (return what is passed into it!)
  7. Set the UrlHelper in your controller to: new UrlHelper(A mock for request context with the above mocked, A route collection which has your applications routes registered into it);

Quite a strange an bizarre set of steps, but it’s what’s required to get around the core implementation within ASP.NET MVC. Maybe they will make it easier to test in the future…

With the above code snippet, I can do the following two lines of code to automatically get a controller with everything mocked correctly (not to mention any interfaces in it’s constructor automatically set to an NSubstitute Mock!):

var autoMock = AutoMockContainer.Create();
var controller = autoMock.GetController<HomeController>();

Read More