This is the second part of my Umbraco 7 unit testing series. Nowadays, everyone by now understands the importance of unit testing, however, on CMS based projects I think a lot of companies drop the ball and don't spend enough time on unit tests. Now, I'm not too sure if people still find it too difficult on CMS projects, or, people don't understand it, so in today' guide I'm going to cover how to ensure that your website is unit testable.
This guide assumes that you have a website structure that's similar to this, How To Create A Global View Model For Umbraco With uSitebuilder and that you have structure map installed followed by this guide, How To Set-Up Structure Map With Umbraco 7.
If you have ever tried to unit test a web project before, you will have found that whenever you try and put things like the HTTP Context under test, when you run your unit tests they blow up as things that have not gone through ISS aren't initialised correctly. This makes perfect sense because when you run your code via IIS, the server does a lot of processing and setting up of dependencies in the background. When you try to run your code directly in unit tests these things blow up and won't work. In most situations, you get around these issues by mocking these dependencies, however, Umbraco has a few testing skeletons that make it a bit more trickier to test than a standard MVC web project. One example is the lack of dependency injection for the API's.
To use one of the Umbraco API's, a developer has to implement a concrete instance of that API within your codebase to get access to their helper. If you want to unit test your code, then we will need a way to inject any code we want to unit test. For this reason, we will need all the Umbraco dependencies injected.
Unit Testing RenderMvcController
Before we get into the meat of this tutorial, I need to talk about the issues unit testing an Umbraco controller. All Umbraco controller inherit from RenderMvcController. As developers we don't have access to the RenderMvcController code as it's in an Umbraco assembly.
The bad news is that if you try and unit test anything that inherits from RenderMvcController, you will get a context exception. I'll cover how to unit test a controller in a future article, a quick overview is to get a copy of the Umbraco Source, compile it yourself, look in the bin folder and you will get a Test.dll. Test.dll has methods that will allow you to mock the Umbrco context. This is a bit of a pain, so instead I'm going to assume that you will use a factory in your controller and abstract all the logic to a different class so you can unit test it, like this:
This approach makes our lives a lot easier in this tutorial :)
In order to write easy to maintain, non-duplicated testable code, the easy solution is to create some form of central wrapper that we can use to wrap all of the Umbraco API calls up. We'll then need to inject this wrapper somehow so all our controllers, view models etc.. can get access to it without having to duplicate the calling code everywhere. In this tutorial, I'm going to cover a handful of API calls. In your projects, your Umbraco Dependencies will be a lot more in-depth. So, say we might have this code in a controller:
This is the uSiteBuilders API to get an instance of the homepage from the database. Running this code from a unit test would fail because the unit test won't be able to access the database or the context. Instead, we're going to create a uSiteBuilder wrapper in a class called UmbracoDependencies. We will inject UmbracoDependencies into a homepage factory so we can use MOQ to ensure the code doesn't blow up. This probably sounds like a mouthful and if you are not used to dependency injection then these concepts might take you a while to get your head around. First, let's create a wrapper for uSiteBuilder:
This class is very simple, all it does is wrap the uSiteBuilder API GetByNodeId method and returns a result. This class should not have any logic in it, all it should be is forward requests to the API and pass it back. The class has a simple interface:
The interface is required so we can inject the interface into a constructor and then use Moq to Mock it in our tests.
In a normal project, you will have several classes like the one above, you will have one for the Umbraco API for example. From my experience, it's a lot easier to have one central dependency class that you inject in, rather than having to inject 5-10 separate parameters into your constructor. Our Umbraco Dependencies class should look like this:
The interface looks like this:
Setting Up Structure Map
Just in case you missed this step, in your Ioc.cs file within the web projects 'DependencyResolution' folder, you need to make sure you have this config:
So, if we now go back to our code, first we need to inject IUmbracoDependencies into our controller factory class. After that we need to swap out the call to the uSiteBuilder to go via the new dependency class:
In the constructor we have IUmbracoDependencies as a parameter. When the website runs (as long as everything is configured correctly) structure map will inject UmbracoDependencies in. In the CreateHomepageViewModel, instead of using ContentHelper.GetByNodeId we now use umbracoDependencies.USiteBuilderHelper.GetHomepageDocumentType().
You should now be able to run your site and it should load the same as normal. So far the code is pretty simple, all we've done is abstracted the ContentHelper in the USiteBuilderHelper file.
Unit Testing The Code
Now assuming you are using MSTest and Moq we can unit test our code. Before if we ran the code below, we would get an exception.
In TestDependenciesHaveBeenMocked, we're using a mocking framework called mock to fake a call to the Umbraco database and return a new HomepageDocumentType object only if the document id is 1. Next, we call CreateHomepageViewModel passing in 1 and if you run the test above the asset will be true. In TestDependenciesMock_Correctly we pass in 0 as the homepage Id. When this is run, nothing will be returned.
In today's guide, we've gone over the basics of creating a dependency resolver for Umbraco. The dependency resolver is a simple interface/wrapper that just mimics the Umbraco API and forwards and retrieves data exactly the same as the API would. It does not logic. By wrapping up this functionality behind a class, our production code will run exactly the same.
The benefit comes when we write unit tests for the code. Using this wrapper approach, we can then use a mocking framework to fake the results the API call would have otherwise made (and failed under test). This approach means we can now test more of our code.
This approach might seem a bit long-winded at first, especially just to test some code. After you do this once or twice you can then copy the code from project to project and the set-up really won't take you that long on each new build.