Unit

Building Class Composers

Under Construction

This page is under construction and may contain incomplete or incorrect information.

Looking over in the demo project, this example can be found here: FakeTests

public interface IFakeService
{
    int GetOne();
}

[Fakes]
public class FakeTests(Fake<IFakeService> fake) 
{       
    public Fact FakeIsReturnsTheValue()
    {
        fake.CallsTo(x => x.GetOne())
            .Returns(1);

        return fake.FakedObject.GetOne() == 1;
    }
}

What actually happens behind the scence is the implementation of two types:

  • A ZeComposerAttribute generic implementation that points to an instance of a IZeClassComposer class.
  • The IZeClassComposer implementation defined by the ZeComposerAttribute which knows how to take data from the ZeComposerAttribute and create the types the class is dependent on.

A natural implementation includes the LamarContainerAttribute or the FakesAttribute this article digs into.

Building the Composer

For ZeUnit to know how to populate the dependencies of a test class it will look to a collection of IZeClassComposer instances, asking each of the composers for the classes it needs and doing its best to compose from all the response. Here is the FakesClassComposer

public class FakesClassComposer : IZeClassComposer    
{
    protected Dictionary<Type, Func<object>> factory = new Dictionary<Type, Func<object>>();

    public object? Get(Type args)
    {
        var genericType = args.GetGenericArguments().FirstOrDefault();
        if (genericType == null || !args.FullName.StartsWith("FakeItEasy.Fake"))
        {
            return default;
        }
        if (!factory.ContainsKey(genericType)) 
        {
            Type fakeType = typeof(Fake<>).MakeGenericType(new Type[] { genericType });
            factory.Add(genericType, () => Activator.CreateInstance(fakeType)!);            
        }        

        return factory[genericType]();
    }    
}

Part of the big function here is that the IZeClassComposer interface returns the Nullable<object> from the get call, allowing a composer to fail to return a type.

In this case, we are not really interested in any information as this IZeClassComposer is generic looking at the Type args to both be a generic argument and to be of a type FakeItEasy.Fake. And knowing that if we request that type we should make the generic version of new Fake<TType>() something that we do caching the reflection call to the activator into a function.

The Composer Attribute

And the easy part, just creating the marker attribute that lets ZeUnit know that the FakesClassComposer is used by the test class. This can be thought of as the arguments for the constructor, in the case of our FakesClassComposer it has no arguments but other classes might.

public class FakesAttribute : ZeComposerAttribute<FakesClassComposer> 
{
}

A generic and none-reflection version of the same type of class also exists in the form of FakeAttribute<TType> which informs composer composer class also keyed to the TType generic to only create the Fake<TType> when the args request the specific TType type.

public class FakeAttribute<TType> 
    : ZeComposerAttribute<FakeClassComposer<TType>>
    where TType : class
{
}

Breaking the Test Mold

The traditional thinking about tests has some purity standards that in the case of this type of work is really breaking the mold. Test dependencies are the responsiblity of // Assemble but ZeUnit has done away with the traditional view of //Assert and these composer methods are a re-usable method of sharing the //Assemble part of your class.

Do you have a repeating pattern of how you build your fakes? Get it directly inject with a IZeClassComposer class and a quick ZeComposerAttribute marker class and all your tests objects and fakes they need.


Next Section Customizing Reporting