
Since .NET 4.x isn’t quite dead yet, here’s a tip from the glory days of ASP.NET unit testing with NUnit (or whatever you like).
What if you are working on this project with lots of IOC Autofac registration modules? When you refactor code, and add some new dependencies to a class, it’s easy to sometimes forget to add those new registrations to your module.
At the end your code is finished and unit tested, and you think you’re done, until you run the app and *bam*. A runtime error occurs because you’re missing an IOC registration. This gets even sillier when you have different projects with slightly different IOC registrations, so it might end up working on one project, but not on another.
So how do you go about testing such a thing?
The trick is to create a unit test that registers the same IOC dependencies as you do in your project(s), and then instantiate your controllers (or other classes) using the IOC framework. This will start throwing exceptions if you’ve forgotten to register the new dependency, and you will catch it as soon as the tests run. Sweet test automation indeed.
The tricky bit is that your tests are not running inside a web request, which handles the lifetime scope of your IOC objects. So you’ll have to fake a request scope yourself in your test to be able to construct all necessary objects.
Luckily, it’s quite easy to do this in your unit tests.
Here’s an example of what that could look like, using NUnit. See the comments for more details.
public class AutofacMvcControllerResolvingTest
{
// The Autofac lifetime scope, which keeps tracks of the created objects.
protected ILifetimeScope Scope { get; set; }
[SetUp]
public void Setup()
{
// Here we setup our IOC container, by adding
// all modules you normally use in your project.
Builder = new ContainerBuilder();
Builder.RegisterModule<YourAutofacModule>();
var container = Builder.Build();
// Now we create our scope.
Scope = container.BeginLifetimeScope("httpRequest");
}
[TearDown]
public void TearDown()
{
// Cleanup the scope at the end of the test run.
Scope.Dispose();
}
// The TestCase NUnit attribute is handy to list a
// number of values which will be passed into the test.
// That way you only need to write one test, instead of
// a test per class type.
[Test]
[TestCase(typeof(FooController))]
[TestCase(typeof(BarController))]
public void Test_If_Controller_Resolves(Type controllerType)
{
// We create the given type using the IOC scope.
var controller = Scope.Resolve(controllerType);
// Assert it isn't null, although if your registrations are wrong,
// the above line will thrown an exception.
Assert.IsNotNull(controller);
}
}