In this tutorial, you will learn some strategies that will allow you to unit test your Umbraco V7 website. Every developer understands the importance of unit testing, however, when I take over a legacy project, they tend to have minimal to no test coverage. There are loads of reasons why teams don't test. Lack of knowledge, lack of experience and time pressures are the main excuses. Whatever your reasons for not testing, in today's guide, I will hopefully change your mindset. I'm going to cover how to ensure that your Umbrac powered website is unit testable. If you want to learn how to improve your Umbraco projects architecture, reduce the number of bugs when you release and reduce the time it takes you to ship code into production, read on 🔥🔥🔥

This guide assumes that you have these things enabled within your project:

The Challange Of Testing Umbraco APIs

The main challenge of CMS testing is that many of the APIs and things like the HTTP Context need to be mocked otherwise they break your unit tests. This makes perfect sense because when you run your code via a web server, the ASP.NET frameworks request pipeline does a lot of processing. During a page request, a lot of values and configurations are set up and enabled. When you try to run your code directly in a unit test these set-up tasks are not run. This means testing something like a controller is only possible by using a mocking framework, like Moq.

Life in Umbraco V7 is also slightly harder as Umbraco does not support dependency injection out-of-the-box. This means that it will take a little longer to write testable code in Umbraco, compared to a standard vanilla MVC web project. One example of this is the lack of dependency injection for the Umbraco APIs. In a lot of instances, you access the Umbraco API using a singleton. The Umbraco APIs are not written to interfaces, a key point for mocking to work. It is still possible to unit test Umbraco code, however, you need a way to inject the APIs into a controller so that can be mocked. This means that you will need to write wrapper classes for all Umbraco APIs you use in areas of code that you want to test. Be warned, you will need to wrap a lot of the Umbraco APIs yourself 😞

The Challange Of Testing RenderMvcController

In Umbraco yoru page controllers will inherit from RenderMvcController. As developers, we don't have access to the RenderMvcController code. Its code shipped with Umbraco within a Umbraco assembly. The bad news is that if you try and unit test anything that inherits from RenderMvcController, in your test code 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 the project yourself. After a successful build, look in the bin folder and you will see an assembly called Test.dll. Test.dll has methods in it that will allow you to mock the Umbraco context. Yes, this is a bit of a pain and it might put you off testing.

Instead, of having to do these painful tasks, an easier approach is to change how you write your controllers. To make testing easier, use a factory in your controller. Abstract all your business logic to a different class. This means you can skip testing your controllers and only unit test the factory code. While not ideal, this approach will allow you to test your code without a lot of hassle. You can write code, like achieve this using this code:

I will assume you will follow this technique, as it makes our lives a lot easier in this tutorial 😊

Writing Wrapper For Umbraco Dependencies

We need to access all the Umbraco APIs via wrappers, what is the best architecture to make this happen? I think the easiest option to access wrappers in your custom code is to create one giant central wrapper that you can inject into any class that will give you wrapped access to any of the Umbraco APIs that you need to use. This single wrapper architecture will make it easy to mock your code and write tests. In this section, I'm going to cover how to build this central wrapper using a handful of API calls you will likely need to access. I have not included everything and in your projects, your dependencies wrapper will be a lot more in-depth. Lets us say you want to access ContentHelper.GetByNodeId in code. This line would make your unit test blow up:

The API above is supplied with a package called uSiteBuilder. This API can be used to get an instance of the homepage from Umbraco. Running this code within a unit test would not work. The code won't be able to access the database or the HTTP context so the API will throw an exception. To make this code testable, we're going to create a wrapper called UmbracoDependencies. We will wrap the API call and then inject it into the homepage factory to make our code testable. First, let's create the wrapper:

This class is very simple, all it does is wrap the uSiteBuilder API GetByNodeId method and returns a result. A wrapper should not contain any logic. All it should do is forward requests to the API and pass any returned data back, job done. To make the class mockable it needs to implement an interface. The interface is simple enough to write:

With this interface defined, we can use dependency injection with the wrapper to access the wrapper in our custom code. We can also use Moq in our tests to run the code within a unit test without it blowing up. In a normal project, you will need to create a few wrappers like like the one above. You will basically create one per Umbraco API.

From my experience, it's a lot easier to have one central dependency class to access all of your wrappers, rather than having to inject 5-10 separate dependencies everywhere. Our Umbraco Dependencies class should look like this:

The interface looks like this:

Setting Up Structure Map

In order for the dependency injection framework to inject IUmbracoDependencies correctly, you need to configure it. I assume you are using StructureMap. Within Ioc.cs found in the DependencyResolution folder, you need to add a rule:

This rule tells StructureMap that when it sees a constructor with IUmbracoDependencies create an object to type UmbracoDependencies and inject it 💥

Going back to our code example, we need to inject IUmbracoDependencies into the factory class.  After that, we need to swap out the code that uses the API call directly and make it use the wrapper instead:

In the constructor, we use IUmbracoDependencies as a constructor parameter. When the website runs (as long as everything is configured correctly) structure map will create an object of type UmbracoDependencies and inject it. In CreateHomepageViewModel, instead of using ContentHelper.GetByNodeId we now use umbracoDependencies.USiteBuilderHelper.GetHomepageDocumentType(). You should now be able to run your site and the functionality should work as before. The code change is pretty simple, all we've done is abstract the call to ContentHelper to use a wrapper. The wrapper is also injected using StructureMap. The power of this change is that you can now easily unit test your code 💥

Unit Testing The Code

We can unit test the code.  Before if we ran the code below, we would get an exception.

This code is using MSTest and Moq. In Test_Dependencies_Have_Been_Mocked, we're using a mocking framework called Moq to fake a call to the Umbraco database and return a new HomepageDocumentType object only if the document Id is 1. Next, the code calls CreateHomepageViewModel passing in 1 as the Id. If you run the test above the asset will be true. In Test_Dependencies_Mock_Correctly the value 0 is passed in as the homepage Id. When this is code run, nothing will be returned.

In this tutorial, you have learned how a simple change in architecture allows you to write testable code. All it takes is a slight tweak to your architecture and you will create infinitely more robust 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. Happy Coding 🤘