JustMock the Sitefinity context
Creating unit tests for your Sitefinity website can be a tough task. If we want to write a unit test that has added value to our project, we want them to be based on the Sitefinity context. But how do we get this context when we are in a disconnected environment? Here is one way how…
At Suneco we believe that we should write unit tests with maximum value for our project. And in order to do that we need to mock the Sitefinity context.
Why do we need the Sitefinity context?
To answer this question we will take a look at our main reasons for creating unit tests.
- Unit tests allow us to make changes more quickly. After changing the solution the unit tests tell us if the application’s functionality still stands. Unit tests allow us to perform tests automatically instead of manually.
- Development is done way more quickly because we do not need to start the website every time we want to test a specific component. This saves us the initial site load time after a build. The Sitefinity developers among us know that this could take a minute or two.
- Unit tests allow us to check integrated (external) systems to provide their functionality as expected by the solution.
When we take a look at a common website project we find a great deal of logic in the business layer. We need to cover the business layer’s functionality in unit tests if we want to make a profit of the above advantages.
This business layer is based on the Sitefinity API which requires a Sitefinity context with a live database connection to perform the well-known CRUD operations.
An abstract layer needs to be created that acts like a data acces layer to return mocked data from the Sitefinity context. This layer has its own implementation in the website project and returns live-Sitefinity data. Our testproject on the other hand is a disconnected environment so the implementation of the data access layer needs to return mocked-Sitefinity data.
We use the dependency injection framework Ninject to determine which instance of the data access layer will be used for each project. Sitefinity Feather also uses Ninject and with their implementation you also have the ability to inject controller instances.
We create the ISitefinityLayer in our business project and create methods for getting, inserting and updating.
It is important that you do nothing more than just pass Sitefinity API functionality in the implementation of this layer. No custom logic is allowed here because that is the responsibility of the business layer. The data access layer exists only to be able to mock the Sitefinity context.
The implementation of this interface returns raw Sitefinity data in the business project:
In our test project we need the implementation of the Sitefinity data access layer to return mocked Sitefinity data.
Mocking Sitefinity data with JustMock
Once you go wild with the JustMock mocking framework, you will realize that the tooling is pretty powerful.
JustMock is the most reasonable choice as a mocking framework because it is also made by Progress / Sitefinity. So we expect it to go hand in hand for any unit test challenge. Besides that, most of the documentation online about Sitefinity and unit tests uses JustMock. Once you go brutal-mode with mocking, you can benefit from the OpenAccess Mocking feature in JustMock to fake the target data access layer without worrying about its dependencies.
We really need a Mocking framework to return mocked data because a lot of properties in the Sitefinity objects, like the Title property, cannot be get or set when it isn’t mocked.
So the following code will result in a TargetInvocationException because most of the BlogPost properties require a connected Sitefinity context:
But the following code will work properly:
The next thing we need to do is to make use of the Sitefinity data access layer in our business project instead of the Sitefinity API.
For Ninject: we tell the website project to bind the SitefinityLayer instance on ISitefinityLayer and in the test project we bind the SitefinityMockedLayer. There is also a second constructor to provide the ability to load a custom layer.
NinjectFactory.xml in the website project:
NinjectFactory.xml in the test project:
The mocked layer will be used to serve the Sitefinity mocked data when the BlogManager is used in the testmethod, because the testproject is configured to instantiate the SitefinityMockedLayer when ISitefinity is resolved.
There will be situations where you want to test on another mocked set than the default. For instance when we want to test our logic on an empty data scenario. In this case we use constructor injection to load a custom Sitefinity data layer that returns empty collections to the BlogManager.
In this blog we have seen one way to Mock a substitute for the Sitefinity context. It requires an extra data layer which can be seen as a wrapper for the Sitefinity data access layer. The extra layer is a technical overhead but it contains no logic and it enables us to unit test the business layer in a proper way.
Onze technische blogs zijn in het Engels. Dit doen wij omdat wij menen dat technische kennis van Sitecore en Sitefinity grensoverschrijdend moet zijn. Wij leren veel van buitenlandse developers, wij delen onze kennis ook graag met hen. Mochten er in de code fouten zitten of punten ter verbetering, dan gaan we graag het gesprek aan.