Skip to Main Content
Customer Feedback

We love feedback from you on our products and the problems in your daily work that you would like us to solve. Please describe the challenge you're encountering and your desired outcome. Be as detailed as possible.

For technical issues or bugs please head to Support or our Developer Community. You can assign up to 20 votes in total. Thank you for your feedback.

Status explanation: 'Future Consideration' = Continuing to collect further feedback, not planned at this time. 'Investigating' = Prioritized for deeper customer and feasibility investigations ahead of planning development.


We are pleased to announce that beginning on Tuesday, March 25th, we are launching a new feedback experience for our customers!

The new experience should transition over seamlessly, but please be aware that short interruptions to our feedback portal may occur on March 25th between 2:30-4:30pm EDT.


All the best, your Optimizely Product Team

Created by Guest
Created on Feb 25, 2025

Optimizely.Graph.Client ConventionRepository is impossible to mock for a unit test

I have recently started using Optimizely Graph Client (Using the latest: 1.4.0). I have created a separate graph conventions field for each component that configures how the component will get indexed by the graph.

/// <summary>

/// Conventions for the accordion blocks

/// </summary>

public class AccordionGraphTypeConventions : IGraphTypeConventions

{

/// <summary>

/// Adds conventions for the accordion blocks

/// </summary>

/// <param name="conventionRepository">The conventions repository</param>

public void Configure(ConventionRepository conventionRepository)

{

// Ensure we have the repository

ArgumentNullException.ThrowIfNull(conventionRepository);

// Configure the accordion grouping block

conventionRepository?.ForInstancesOf<AccordionGroupingBlock>()?

.Set(p => p.Title, IndexingType.Searchable)

.Set(p => p.Description, IndexingType.OnlyStored)

.Set(p => p.IsFaq, IndexingType.Queryable)

.Set(p => p.Items, IndexingType.OnlyStored)

.ExcludeField(p => p.UniqueId);

// Configure the accordion item block

conventionRepository?.ForInstancesOf<AccordionItemBlock>()?

.Set(p => p.Title, IndexingType.Searchable)

.Set(p => p.Text, IndexingType.OnlyStored)

.ExcludeField(p => p.UniqueId);

}

}


This works fine. The problem I have encountered is when I try to write unit tests for this. In versions prior to 1.4.0 I was able to write a test like this:


public class AccordionGraphTypeConventionsTests : BaseTest

{

[Fact]

public void Configure_ConfigureAccordionGroupingBlock_ConfigurationIsSet()

{

// Arrange

var conventionRepository = Substitute.For<ConventionRepository>();

var accordionGraphConventions = new AccordionGraphTypeConventions();

// Act

accordionGraphConventions.Configure(conventionRepository);

// Assert

var fieldConventions = conventionRepository.GetFieldConventions(typeof(AccordionGroupingBlock));

foreach (var conventionType in fieldConventions)

{

var excludedFields = conventionType.GetExcludedFields();

var excludedFieldsArray = excludedFields as string[] ?? excludedFields.ToArray();

excludedFieldsArray.Length.Should().Be(1);

excludedFieldsArray.FirstOrDefault().Should().Be(nameof(AccordionGroupingBlock.UniqueId));

var indexedFields = conventionType.GetFieldsWithIndexingSetting();

var indexedFieldsArray = indexedFields as string[] ?? indexedFields.ToArray();

indexedFieldsArray.Length.Should().Be(4);

indexedFieldsArray.Should().Contain(nameof(AccordionGroupingBlock.Title));

indexedFieldsArray.Should().Contain(nameof(AccordionGroupingBlock.Description));

indexedFieldsArray.Should().Contain(nameof(AccordionGroupingBlock.IsFaq));

indexedFieldsArray.Should().Contain(nameof(AccordionGroupingBlock.Items));

conventionType.GetIndexingType(nameof(AccordionGroupingBlock.Title)).Should().Be(IndexingType.Searchable);

conventionType.GetIndexingType(nameof(AccordionGroupingBlock.Description)).Should().Be(IndexingType.OnlyStored);

conventionType.GetIndexingType(nameof(AccordionGroupingBlock.IsFaq)).Should().Be(IndexingType.Queryable);

conventionType.GetIndexingType(nameof(AccordionGroupingBlock.Items)).Should().Be(IndexingType.OnlyStored);

}

}

}

This way I can ensure that configurations work, and more importantly, it gives me the freedom to change things in the future and catch any problems that might arise. But after the update to 1.4.0 this has stopped working because of changes made to the ConventionRepository.

Specifically, the constructor and all the collections in the class are private and/or internal.

public class ConventionRepository

{

private readonly IDictionary<Type, ConventionType> _fieldConventions;

private readonly HashSet<Type> _includedInterfacesAndAbstractTypes;

private readonly HashSet<Type> _excludeTypes;

private readonly ConventionOnlyInclude _conventionOnlyInclude;

internal EventHandler<ConventionChangeEventArgs> OnConventionsChange;

internal ConventionRepository()

{

this._fieldConventions = (IDictionary<Type, ConventionType>) new Dictionary<Type, ConventionType>();

this._includedInterfacesAndAbstractTypes = new HashSet<Type>();

this._excludeTypes = new HashSet<Type>();

this._conventionOnlyInclude = new ConventionOnlyInclude(this);

}

.........

}

So any attempt to mock fails and I cannot get access to the internal collections. Is there any way that an interface could be extracted from this repository so that it could be mocked for a test? A lot of the other Optimizely repositories are set up this way.