Try our conversational search powered by Generative AI!

Mark Stott
May 26, 2022
(1 votes)

Unit Testing with Dynamic Data Store in CMS 12 - Part 1


If you've never heard of it, the Dynamic Data Store (DDS) which is a component that offers an API and infrastructure for CRUD operations of custom data objects.  It allows developers to access and store data without needing to provision custom tables or databases using either classes or property bags which are stored within shared tables contained in the CMS database.

Optimizely also use the same functionality for some of their own features.  For example, Optimizely Search & Navigation comes with a feature known as Best Bets which allows content editors to provide search suggestions for given search terms.  Each Best Bet has it's own entry inside of the Dynamic Data Store.

This article is the first of two articles showing developers how they can unit test with the Dynamic Data Store, each with it's own separate technical approach.  Both approaches are valid, but the choice in approach may come down to how many different operations you are under taking with the Dynamic Data Store.  Part 1 deals with the direct mocking of the Dynamic Data Store objects while Part 2 deals with abstraction of the Dynamic Data Store behind multiple interfaces.

The Repository Under Test

Lets assume we have a custom data object that we want to store in the Dynamic Data Store as follows:

public class MyCustomDataObject : IDynamicData
   public Identity Id { get; set; }
   public string UniqueText { get; set; }
   public string SomeOtherText { get; set; }

The object MyCustomDataObject has an Identity property in order to meet the IDynamicData interface which is the minimum requirement for storage within the Dynamic Data Store.  The UniqueText property should be unique to that instance of the MyCustomDataObject, the SomeOtherText is just additional information to be stored with that record.

A repository that handles the saving of MyCustomDataObject records may look something like this:

public class MyCustomDataObjectRepository
   private readonly DynamicDataStore _dataStore;

   public MyCustomDataObjectRepository(DynamicDataStoreFactory dataStoreFactory)
       _dataStore = dataStoreFactory.CreateStore(typeof(MyCustomDataObject));

   public void Save(Guid id, string uniqueText, string someOtherText)
       var matchingRecord = _dataStore.Find<MyCustomDataObject>(nameof(MyCustomDataObject.UniqueText), uniqueText).FirstOrDefault();

       if (matchingRecord != null && !matchingRecord.Id.ExternalId.Equals(id))
           throw new EntityExistsException($"An entry already exists for the unique value of '{uniqueText}'.");

       var recordToSave = Guid.Empty.Equals(id) ? CreateNewRecord() : _dataStore.Load<MyCustomDataObject>(Identity.NewIdentity(id));
       recordToSave.UniqueText = uniqueText;
       recordToSave.SomeOtherText = someOtherText;

   private static MyCustomDataObject CreateNewRecord()
       return new MyCustomDataObject { Id = Identity.NewIdentity() };

Unit Testing

In order to unit test the repository behaviour, we need to mock the Dynamic Data Store.  Optimizely does not provide any interfaces to assist with the writing of unit tests and we have to mock implementations instead. 

The mocking of implementations can come with it's own complications.  With a mock behaviour of 'strict', the mocked object will behave like the true implementation and will throw exceptions as expected.  With a mock behaviour of 'loose', no exceptions will be thrown and default values will be returned as necessary.  The default mock behavior of any mocked object is actually the strict behaviour.

The strict mock behavior makes unit testing of the Dynamic Data Store impossible with exceptions being thrown during the set up of the test.  So in the following setup method, I have mocked the StoreDefinition, the DynamicDataStore and the DynamicDataStoreFactory with a loose mock behavior.  This is done by supplying the behavior in the mock constructor. The additional parameters applied to the mock constructors are default types which fulfil the constructor of the implementation being mocked.

public class MyCustomDataObjectRepositoryTests
   private Mock<DynamicDataStoreFactory> _mockDynamicDataStoreFactory;

    private Mock<DynamicDataStore> _mockDynamicDataStore;

    private Mock<StoreDefinition> _mockStoreDefinition;

    private MyCustomDataObjectRepository _repository;

   public void SetUp()
       _mockStoreDefinition = new Mock<StoreDefinition>(
           new List<PropertyMap>(0),

        _mockDynamicDataStore = new Mock<DynamicDataStore>(

       _mockDynamicDataStoreFactory = new Mock<DynamicDataStoreFactory>();
       _mockDynamicDataStoreFactory.Setup(x => x.CreateStore(typeof(MyCustomDataObject)))

        _repository = new MyCustomDataObjectRepository(_mockDynamicDataStoreFactory.Object);

At this point we are now free to write unit tests as easily as we would do when mocking interfaces.  In the following test example, an existing record is created and is set to be the result of the mocked Find method against the DynamicDataStore. When we try to save a record with a matching uniqueText, the desired outcome is that an EntityExistsException is thrown and our assertion is constructed to prove that.

public void GivenUniqueTextExistsAgainstAnotherEntity_ThenAnEntityExistsExceptionShouldBeThrown()
   // Arrange
   var uniqueText = "i-am-unique";
   var someOtherText = "some-other-text";

   var existingRecord = new MyCustomDataObject
       Id = Guid.NewGuid(),
       UniqueText = uniqueText,
       SomeOtherText = "original-other-text"

    _mockDynamicDataStore.Setup(x => x.Find<MyCustomDataObject>(It.IsAny<string>(), It.IsAny<object>()))
                           .Returns(new List<MyCustomDataObject> { existingRecord });

    // Assert
   Assert.Throws<EntityExistsException>(() => _repository.Save(Guid.Empty, uniqueText, someOtherText));


In order to unit test against the Dynamic Data Store, you must do the following in order to write unit tests as normal:

  • Mock the StoreDefinition with MockBehavior.Loose.
  • Mock the DynamicDataStore with MockBehavior.Loose and pass in the mock of the StoreDefinition.
  • Mock the DynamicDataStoreFactory with either mock behavior and set up the CreateStore method to return the mocked DynamicDataStore.

To be continued in Part 2...

May 26, 2022


Please login to comment.
Latest blogs
New Series: Building a .NET Core headless site on Optimizely Graph and SaaS CMS

Welcome to this new multi-post series where you can follow along as I indulge in yet another crazy experiment: Can we make our beloved Alloy site r...

Allan Thraen | Jun 14, 2024 | Syndicated blog

Inspect In Index is finally back

EPiCode.InspectInIndex was released 9 years ago . The Search and Navigation addon is now finally upgraded to support Optimizely CMS 12....

Haakon Peder Haugsten | Jun 14, 2024

Change the IP HTTP Header used for geo-lookup in Application Insights


Johan Kronberg | Jun 10, 2024 | Syndicated blog

Copying property values

In this article I’d like to show simple Edit Mode extension for copying property values to other language versions. In one of my previous blogposts...

Grzegorz Wiecheć | Jun 8, 2024 | Syndicated blog