Automated Testing of ASP.NET Web API and MVC applications

Yesterday I started working on my first professional usage of ASP.NET Web API and as part of that created a handy base class to perform full-stack unit and/or integration testing of controller actions in-process. It was based on some stuff I found online, but put my own flair on so I thought I would share it here in case anyone else found it useful. While I’m at it I thought I’d briefly outline my testing strategy for most MVC applications I write.


When I’m testing an ASP.NET MVC application I have had good mileage with covering the following (this is a combination of what you might consider to be integration and unit tests):

  • Routes: Typically you aren’t going to change the URLs in your application (because then you would be dealing with potential search engine optimisation and bookmarking issues) so if they do change it’s a good indication that (in an MVC application) you’ve added a new route definition that has broken some existing definitions. I will typically test the URLs for all controller actions (including mapping route values to action input parameters) and test that calling Url.Route with the same parameters results in the same route being generated. This kind of testing has saved my bacon many times in the past and it is quick and effective to write the tests whenever adding a new controller action using the code I use (a version of MVCContrib.TestHelper that I modified to use NSubstitute). It’s particularly handy when you have areas in your application because they have a nasty tendency of breaking your routes.
  • Controllers: If any particular controller action is more than a few lines of code (and thus it isn’t bleedingly obviously that it’s either correct or not correct just by looking at it), then like all complex business logic I try and unit test the controllers. I do this using the Fluent MVC Testing library that I created because it’s terse and easy to write these tests.
  • Controller Instantiation: As previously blogged.
  • Filters, Filter Providers and Model Binders: I will typically unit test these, for an example see my previous post about unit testing filter providers.
  • UI Testing: If the circumstances of the project allow for it then well-placed full-stack tests provide a lot of extra confidence. My fellow TestStacker Mehdi Khalili has a brilliant slide deck on this.
  • Database Layer: I perform tests against individual queries / commands / repository methods by doing a full integration test against a real database and wrapping the whole thing in a Transaction Scope so I can roll-back any changes in the test teardown. This ensures the test database always remains clean (read: empty) and each test can work in isolation.
  • Database migrations: I like to include one test that brings the test database to version 0 and then back up to the latest version so that if you ever need to use your down migrations then you have confidence they work (as well as continuing confidence that all of your up migrations work).
  • Business logic / services / domain logic: I will always unit test this
  • Infrastructure code: Where practical I try and unit test this. Sometimes this code is tested as a result of other tests e.g. the database tests and controller instantiation tests

If there are any particular types of testing that you would like me to do a more detailed blog post feel free to add a comment below.


The tests above have a nice mixture of unit and integrations tests and I find that they combine to provide a good level of confidence and coverage as the codebase evolves. I have only really played around with Web API in my spare time so far so the following recommendations are likely to evolve over time, but this is my current gut feel about this kind of testing.

Firstly, there are a few good posts I came across that give a broad idea of the different ways in which you can test Web API:

And then my initial approach / thoughts:

  • Routes:The other day I stumbled across a library someone had created to do route testing for ASP.NET Web API and while I’m not a fan of the syntax they created (vs MVCContrib.TestHelper style syntax) it’s a good start in this direction. For the moment I’m thinking (as you will see) that I can take care of route testing implicitly. Furthermore, at least for my current project, the number of routes I’m dealing with doesn’t necessitate route testing. If the routes that you deal with are complex enough and or large enough in number then unit testing routes will likely provide a lot of value.
    Controllers: There is less need for a library like Fluent MVC Testing with Web API since most of your controllers will simply return the data that they queried directly and rely on formatters to give the correct response. This makes unit testing the controllers really simple. As for route testing the initial approach I’ve settled on will cover this testing anyway.
  • Controller Instantiation: For the same reason this is valuable for ASP.NET MVC projects I think this is valuable (and just as easy to test). In my current project I haven’t bothered creating this yet since I’m only dealing with one controller with a couple of dependencies so I don’t have any code for this.
  • Filters, etc.: I think there is value in unit testing these things in the same way as there is for MVC applications. In this instance the approach I’ve settled on tests these as well because it’s a full stack test. This is fine for simple filters / formatters etc., but if you have complex ones then I highly recommend unit testing them as well.
  • UI Testing: This one is interesting, because at first thought there is no UI to test so this isn’t applicable. However, the way I see it, the equivalent in API tests are testing from the viewpoint of the client/consumer e.g. if I make a get request to this URL then I expect that object in JSON format. If you are producing an API according to a specification then this is the viewpoint the specification is written in and depending on how you do things, the acceptance criteria for the work you are doing will also be in terms of this. For these reasons, I think in some ways, while it is integration testing, testing the full stack from the viewpoint of a client provides a lot of bang for buck. As I will explain further below, this is the approach I have decided to initially take. I should note that the traditional pain points of UI testing for MVC applications (cross-browser differences, really slow, out of process so you can’t easily mock things, etc.) can easily be mitigated when doing this testing, which is why I find it a suitable approach in lieu of some of the other testing I might normally do.
  • Database / business logic / infrastructure: None of this changes.

The approach I’ve taken for Web API testing

This is heavily based on the ASP.Net Web Api Integration Tests With Self Hosting post I linked to above. The problems I had with the code shown in that post was:

  • The route was defined in the test rather than re-using the routes you define in your application
  • The test itself is defined within a lamdba
  • There was no abstraction of the code to set up the server
  • The base URL was specified multiple times
  • The test was really verbose (apart from not abstracting out the server it had a stream reader and WebRequest.Create etc.)

In the end I created a base class (using NUnit, but the same applies to any unit testing framework) that abstracted away the creation of the server as well as the HTTP call. This resulted in tests that were dead simple and very terse (for the moment there is only a get request, but you can easily add other methods and headers etc.). I also exposed the dependency injection so that I could insert mocks to control whether I want to unit test the controller action or integration test it with real dependencies. In this case it uses Autofac, but again the same applies for any DI framework.

Another thing to note is that I’ve baked in support for detecting if Fiddler is currently running and proxying requests through Fiddler in that instance. That way you can seemlessly move your test between your local computer (with or without Fiddler running) and your CI server without changing any code. The fact it proxies through Fiddler makes it really easy to debug exactly what is going on too.

Two other things to note are that you need to change PingController to a controller (or any class really) in the assembly that contains your API controllers and that this assumes you have created a static method inside the RouteConfig class called RegisterApiRoutes that defines the routes for your API.

using System;
using System.Net.Http;
using System.Web.Http.SelfHost;
using Autofac;
using Autofac.Integration.WebApi;
using NUnit.Framework;
using WebApiTesting.App_Start;
using WebApiTesting.Controllers;

namespace WebApiTesting.Tests.TestHelpers
    class WebApiTestBase
        private HttpSelfHostServer _webServer;
        protected IContainer Container { get; private set; }
        protected ContainerBuilder ContainerBuilder { get; set; }
        protected Uri BaseUri { get; private set; }

        private bool _fiddlerActive = true;

        public void TestFixtureSetup()
            var client = new HttpClient();
            catch (Exception)
                _fiddlerActive = false;

        public virtual void Setup()
            BaseUri = new Uri("http://localhost:3000");
            var config = new HttpSelfHostConfiguration(BaseUri);

            ContainerBuilder = ContainerBuilder ?? new ContainerBuilder();
            Container = ContainerBuilder.Build();

            config.DependencyResolver = new AutofacWebApiDependencyResolver(Container);

            _webServer = new HttpSelfHostServer(config);

        protected HttpResponse PerformGetTo(string url)
            var client = new HttpClient();
            var response = client.GetAsync((_fiddlerActive ? "http://ipv4.fiddler:3000/" : BaseUri.ToString()) + url).Result;
            var content = response.Content.ReadAsStringAsync().Result;

            return new HttpResponse { Content = content, Response = response };

        public void Teardown()
            ContainerBuilder = null;
            Container = null;

    class HttpResponse
        public string Content { get; set; }
        public HttpResponseMessage Response { get; set; }

So, how exactly do you use this class? Great question, but first a bit of context. My example will be for a endpoint at /api/ping that takes a GET request and returns the UTC system time in ISO format within an object with a property “Timestamp” along with a 200 OK if the database is up and running or a blank response with a 500 error if the database is not up and running.

Here is my test class:

using System;
using System.Net;
using Autofac;
using NSubstitute;
using NUnit.Framework;
using WebApiTesting.Infrastructure;
using WebApiTesting.Tests.TestHelpers;

namespace WebApiTesting.Tests.Controllers
    internal class PingControllerTests : WebApiTestBase
        private IDateTimeProvider _dateTimeProvider;
        private IPingRepository _pingRepository;

        public override void Setup()
            ContainerBuilder = new ContainerBuilder();
            _dateTimeProvider = Substitute.For<IDateTimeProvider>();
            _pingRepository = Substitute.For<IPingRepository>();
            ContainerBuilder.Register(c => _dateTimeProvider);
            ContainerBuilder.Register(c => _pingRepository);

        public void GivenTheDatabaseIsUpAndRunning_WhenGetToPing_ReturnCurrentTimestampAnd200Ok()
            _dateTimeProvider.Now().Returns(new DateTimeOffset(new DateTime(2012, 11, 4, 12, 20, 6), TimeSpan.Zero));

            var response = PerformGetTo("api/ping");

            Assert.That(response.Response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
            Assert.That(response.Content, Is.EqualTo(@"{""Timestamp"":""2012-11-04 12:20:06""}"));

        public void GivenTheDatabaseIsNotRunning_WhenGetToPing_Return500ErrorWithNoContent()
            _pingRepository.When(r => r.CheckDatabase()).Do(a => { throw new Exception(); });

            var response = PerformGetTo("api/ping");

            Assert.That(response.Response.StatusCode, Is.EqualTo(HttpStatusCode.InternalServerError));
            Assert.That(response.Content, Is.EqualTo(string.Empty));

There are a few things to note:

  • To register the listener to the port you need to run Visual Studio (and your CI test runner) as admin otherwise you will get a could not register port error.
  • I used port 3000, but if you are running as admin and get an error saying that port can’t be registered it then you might have something else on that port so feel free to change.
  • Unfortunately I couldn’t make use of AutoSubstitute, but unfortunately that broke the HTTP server (I imagine because it was giving mocks for things that the server needed real stuff for). The downside of this is that I have to keep track of the dependencies of the controller within the test making the test more verbose.
  • Because I need the container builder before starting up the web server I have to create the container builder in the setup method and register everything that I need to mock for any of the tests there, rather than setting up what needs to be mocked in each individual test.
  • I am setting up and shutting down the web server for each test to isolate them, but if there are a lot of tests this might be too slow and attaching start up to fixture setup or even test assembly set up might be a better option.
  • As mentioned above for now there is only a PerformGetTo method, but it would be easy to support the other things needed.

I’ve uploaded the example source code to Github. Feel free to fork it and play around. If you have any suggestions or improvements feel free to add a comment :)


11 thoughts on “Automated Testing of ASP.NET Web API and MVC applications”

  1. This is a fantastic investigation of webapi testing Rob. Heaps of interesting things to think about. I love the way you are able to test the full stack in-process with one appdomain and I particularly liked your use of fiddler. That’s a really nice touch and opens up lots of possibilities. I liked how you used IoC and nsubstitute too. Reminiscent of the benefits you get from autosubstitute.

    Thanks for the MVC testing strategy too. It’s a great reference that I will point my team mates to in future. Would make some great guidance on the TestStack page….

  2. This is a nice & interesting post.

    Personally though, I feel you shouldn’t use self host for integration testing. For starters, this forces you to run the tests with elevated privileges, which then means if you want to automate this through powershell or build process or any other tool, it means that this particular process also needs to run with elevated privileges.

    Secondly, you end up testing the given operating system’s networking stack which really shouldn’t be tested – since it might differ across different staging environments. As a result you might get dragged into unnecessary debugging efforts across different machines to even get the tests running. Furthermore, testing using self-hosting, doesn’t guarantee that the service will run correctly when web-hosted and vice versa.

    IMHO the best approach is to use in-memory hosting for integration testing (run the whole stack in memory, which is very easy & convenient in Web API( – and then just test the underlying host’s connectivity separately.

    1. Thanks Filip!

      Yep – this isn’t for everyone as you do need admin privileges (which I mentioned :)). My CI server is running as an admin user and we have to run VS as admin because we are using IIS for our dev sites so in my case it’s not an issue.

      Interesting re: OS network stack; in saying that I would say that most of the time the network stack isn’t going to differ too much? I guess the main thing is the value that you get from actually performing a HTTP request and getting the response (i.e. full end-to-end stack test from the client’s perspective) needs to be balanced against the fact it’s not a fully representative test. Given the speed of this testing though, I’m personally satisfied that what I want to test is being tested, and as always there will be other things these tests aren’t testing and they should thus be tested in other ways (e.g. manual smoke testing or automated end-to-end acceptance tests against an actual deployed instance). That is likely to be a lot slower and obviously isn’t in-process so you don’t have control and the same sort of limitations / techniques as web UI testing should be adhered too.

      I’m curious what you mean by in-memory hosting? Do you mean newing up controllers or something else? Do you have a code snippet? :)

      Thanks again!! Really helpful comments that expose some of the limitations of this approach.

      1. I should clarify that from what I said and from what you said perhaps this technique is best used for unit testing the controllers (but unit testing from the client’s perspective)? Maybe integration tests should be ideally performed against an actual environment unless you have so many that it’s too slow and you are willing to forgo some of the real-world things like cross-server communication and deployment on IIS etc.?

      2. One of the most beautiful things abut the architecture of Web API (or rather the new HTTP object model it uses) is the client-server symmetry. The entry point to Web API is HttpServer (in self host its variation is the HttpSelfHostServer) class, which just happens to be inheriting from a MessageHandler.

        HttpClient, can run MessageHandlers on the client. This is useful for example when server gzips the response, and it needs to be decompressed before processing by HttpClient. Anyway, HttpClient does not have to send requests over the wire. It is able to take the handler in its constructor (to facilitate for example the scenario I just mentioned). If you put 2 and 2 together, it’s now obvious, that the HttpClient can actually also take HttpServer in its constructor (since that’s also a handler).

        What you end up with, is the entire pipeline running in memory. Full stack – from the entry point, through all handlers, all filters, and so on. The only difference is you bypass the network stack.
        I blogged about that a while ago –

        1. WOW! That is seriously cool! And it’s definitely a hidden gem.

          I completely agree with what you said about testing the OS network stack now – you are completely right. I’ll try and find some time to play with it and update the post (crediting you of course).

          The only disadvantage I see is you can’t do it through Fiddler, but given I have code to detect if Fiddler is being used I can in that instance use self host so that it’s easy to debug what’s going on :)

  3. I will read in more depth, but our production routes are generated by an extension called AttributeRouting, but this fails in an integration test with NullRefEx. Trying without success thus far to workaround that issue. We need to manually declare routes with this?

    Otherwise, I’ve at least verified that the controller under test can be resolved from the IDepResolver in test. Possibly a custom filter attribute is causing us some issues. Additionally, we could remove Json as well as Xml formatters since this will be raw and in memory.

    Also, how do you tell HttpServer its port number?

    It sounds like a grand idea to include a simple ping controller/test, as well. When it’s working then it should be easy to extend for others, but for sheer mass.


    1. Not sure about why you would get a NRE from Attribute Routing (are you using the built-in one as part of Web API 2?).

      You probably want to keep your xml formatters if you are testing the serialisation of the request and response.

      You tell the HttpServer it’s port from the Uri you pass into the HttpSelfHostConfiguration constructor.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>