2017-09-28

Unittesting custom Sitecore SXA components using FakeDb part 1: Setting up

When you create custom components for Sitecore, you're probably doing so because you've got a piece of logic for rendering certain information that simply isn't provided out-of-the-box. But proving (read: unit testing) that logic can be a bit tricky when everything in your component hooks into the Sitecore API.

Frameworks

For this article, I'm using NSubstitute but this method would work just as well with your mocking framework of choice.

The most important part however is FakeDb. FakeDb allows you to mock items in the Sitecore master database to test your repository and controller.

Mocking the Sitecore context

When you make a custom Sitecore component, there's a lot of "magic" going on in the background.  You can get the current URL, the data item that was configured for the component, even query everything else on the site if you really want to, for some reason.

This magic however also makes for tricky unittesting, because you aren't actually IN Sitecore when running your tests (you can be, by the way, but that would make your tests more like integration tests and that's a whole other part of the testing pyramid).

This post is based off examples shown in a StackOverflow post, but those examples are using the Sitecore.DependencyInjection namespace. When you make SXA components however, you're going to need the Sitecore.XA.Foundation.IoC namespace which behaves similar but slightly, infuriatingly, different.

In the steps below we'll set up unit testing for a model repository.

1. Set up your references

Most of the assembly references you need can be pulled off the official Sitecore NPM feed, but you'll need three extra;
  • Sitecore.XA.Foundation.Common
  • Sitecore.XA.Foundation.Editing
  • Sitecore.XA.Foundation.IoC
These can be found in your Sitecore Website\bin folder.
Other assemblies you'll need that can be obtained from NPM are
  • Sitecore.FakeDb
  • Sitecore.Kernel
  • Sitecore.Analytics
  • Sitecore.Analytics.Core
  • Sitecore.Analytics.Model
  • Sitecore.Logging
  • Sitecore.Mvc
  • Sitecore.Nexus
  • NSubstitute (or your choice of mocking framework, but I'll be using this in my examples)

2. Set up dependency injection

I suggest creating a base test class that your unit test classes derive from so you can make most of this plumbing just once. To be able to call FillBaseProperties from the ModelRepository base class your repository likely extends, this is the minimum amount of services you need to set up:

protected virtual void SetupServices(Db fakeDb)
{
    var mockServiceCollection = new ServiceCollection();
    new Sitecore.DependencyInjection.DefaultSitecoreServicesConfigurator().Configure(mockServiceCollection);

    mockServiceCollection.AddTransient(provider => MockRendering(fakeDb));
    mockServiceCollection.AddTransient(provider => MockPageContext(fakeDb));
    mockServiceCollection.AddTransient(provider => MockIControlEditabilityService());
    mockServiceCollection.AddTransient<IMyRepository, MyRepository>();

    var serviceProvider = mockServiceCollection.BuildServiceProvider();
    ServiceLocator.SetLocatorProvider(new Locator(serviceProvider));
    
    var instance = typeof(FieldTypeManager).GetField("Instance", BindingFlags.Static | BindingFlags.NonPublic);
    var instanceValue = instance.GetValue(null) as Sitecore.DependencyInjection.LazyResetable<Sitecore.Abstractions.BaseFieldTypeManager>;
    instanceValue.Value.Initialize();
}

3. Mocking

In the next post I'll go into mocking your services and items.

4 comments: