2017-10-11

Unittesting custom Sitecore SXA components using FakeDb part 2: Mocking and testing

In part 1, I discussed services necessary to get your repository unittests to work if you use ModelRepository.FillBaseProperties() in your code. In this part, I'll show how to mock these services and round up to demonstrate a working test.

Mocking Sitecore services

Using NSubstitute, we can easily create mocks for the necessary service interfaces to use in the mock ServiceCollection. IRendering and IPageContext :

private static IRendering MockRendering(Db fakeDb)
{
 var renderingMock = Substitute.For<IRendering>();
 renderingMock.DataSourceItem.Returns(fakeDb.GetItem(ItemId));
 return renderingMock;
}

private static IPageContext MockPageContext(Db fakeDb)
{
 var contextMock = Substitute.For<IPageContext>();
 contextMock.Current.Returns(fakeDb.GetItem(ItemId));
 return contextMock;
}

private static IControlEditabilityService MockIControlEditabilityService()
{
 var mock = Substitute.For<IControlEditabilityService>();
 var editabilityMock = Substitute.For<IControlEditability>();
 editabilityMock.Editable.Returns(false);
 mock.GetControlEditability(Arg.Any<IRendering>()).Returns(editabilityMock);
 return mock;
}

Note that both IRendering and IPageContext get the item you're going to mock per unittest and that's already in the FakeDb. The items they return should be the same and be easily specifyable in each TestMethod, so I've added this line to my test baseclass:

protected static ID ItemId = ID.NewID;

This ID is then used to create, add and retrieve a DbItem to and from the FakeDb. This same item also needs to be set as the current item in the Context:

Context.Items["sc_CurrentItem"] = fakeDb.GetItem(ItemId);

Usage in testcases

Because all the mocking work needed to run the tests is done in a baseclass, all you need in unit-specific test class is a way to get your repository (I've made the baseclass using generics so it automatically registers IMyService with MyService as implementation class in the ServiceCollection):

private MyRepository Repository
{
 get
 {
  return ServiceLocator.Current.ServiceProvider.GetService(typeof(IMyRepository)) as MyRepository;
 }
}

and, of course, tying it all up in a testcase, where SetupServices is described in the previous post:

[TestMethod]
public void FillExtraProperties_FillsTitle()
{
 using (var fakeDb = new Db())
 {
  // Arrange
  var item = new DbItem("MyItemName", ItemId, SitecoreItemConstants.TemplateId) {
   { SitecoreItemConstants.TitleFieldSelector, "testtitel" }
  };
  fakeDb.Add(item);
  SetupServices(fakeDb).FinalizeSetup();

  // Act
  var result = Repository.GetModel() as MykModel;

  // Assert
  Assert.IsNotNull(result);
  Assert.AreEqual("testtitel", result.MyTitle);
 }
}

And there you have it! If there's anything still unclear with the process don't hesitate to drop a comment. Happy testing!