Autofixture: ConcurrentDictionary

Created on 24 Apr 2020  ·  6Comments  ·  Source: AutoFixture/AutoFixture

Hi,
When I use autofixture to generate a Dictionary<T, U> I get values populated in it by default, but with a ConcurrentDictionary<T, U> I don't.

Is this by design & I should use a specimen builder to alter that behaviour myself, or is it a missing feature or bug?

Most helpful comment

Hello,
I cannot tell the reasons behind this, but it looking at the source code the supported collections are hard coded.
So it is not something like "does type implement IDictionary", it is "is type Dictionary<,>". Therefore ConcurrentDictionary does not work.
You dont need to create your own specimenbuilder, you can use what is already there:

      var fixture = new Fixture();

      var query = new ModestConstructorQuery();
      var methodInvoker = new MethodInvoker(query);
      var dictionaryFiller = new DictionaryFiller();
      var postProcessor = new Postprocessor(methodInvoker, dictionaryFiller);
      var exactTypeSpecification = new ExactTypeSpecification(typeof(ConcurrentDictionary<,>));
      var specimenBuilder = new FilteringSpecimenBuilder(postProcessor, exactTypeSpecification);

      fixture.Customizations.Add(specimenBuilder);

All 6 comments

If anyone else comes accross the same issue, I've written a specimen builder for this:

public class ConcurrentDictionaryGenerator : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        Type type = request as Type;
        if (type == null)
        {
            return new NoSpecimen();
        }

        Type[] typeArguments = type.GetTypeInfo().GetGenericArguments();
        if (typeArguments.Length != 2 || typeof(ConcurrentDictionary<,>).MakeGenericType(typeArguments) != type)
        {
            return new NoSpecimen();
        }

        Type nonConcurrentDictionaryType = typeof(Dictionary<,>).MakeGenericType(typeArguments);
        IDictionary nonConcurrentDictionary = (IDictionary) context.Resolve(nonConcurrentDictionaryType);

        IDictionary concurrentDictionary = (IDictionary) Activator.CreateInstance(type);

        foreach (object key in nonConcurrentDictionary.Keys)
        {
            object value = nonConcurrentDictionary[key];
            concurrentDictionary.Add(key, value);
        }

        return concurrentDictionary;
    }
}

Hello,
I cannot tell the reasons behind this, but it looking at the source code the supported collections are hard coded.
So it is not something like "does type implement IDictionary", it is "is type Dictionary<,>". Therefore ConcurrentDictionary does not work.
You dont need to create your own specimenbuilder, you can use what is already there:

      var fixture = new Fixture();

      var query = new ModestConstructorQuery();
      var methodInvoker = new MethodInvoker(query);
      var dictionaryFiller = new DictionaryFiller();
      var postProcessor = new Postprocessor(methodInvoker, dictionaryFiller);
      var exactTypeSpecification = new ExactTypeSpecification(typeof(ConcurrentDictionary<,>));
      var specimenBuilder = new FilteringSpecimenBuilder(postProcessor, exactTypeSpecification);

      fixture.Customizations.Add(specimenBuilder);

The more I learn about the internals of this library, the more I love it

Interesting to know it's only on Dictionary<,> currently & thanks for the built-in way of doing it!

I guess the only remaining question for someone would then be: would this be a good feature to add? Perhaps not for ConcurrentDictionary<,> specifically, but all IDictionary<,> implementations?

Just that I dont spread wrong information, it is is not only Dictionary<,>. I just wanted to point out that the list of types can be found directly in Fixture.cs. E.g. it is also SortedDictionary<,>, but as you already figured out, it is not ConcurrentDictionary<,>.
By all means I would say that a future implementation should check for the interface.

In reality what's hardcoded it's not the support rather the fact that interfaces are relayed to some concrete type. Like IDictionary and IReadOnlyDictionary are relayed to Dictionary, and so on.

Was this page helpful?
0 / 5 - 0 ratings