DEV Community

loading...

TIL: How to register an implementation of a generic interface in AutoFixture

Pedro Osternack Corrêa
C# and JS developer, juggling enthusiast with a coffee addiction.
・2 min read

On a previous post I've used AutoFixture with a auto mocking customization (that would generate mocks for each dependency of the system under test (SUT) that you create through AutoFixture). On that post I had one snippet that used the Register method, like this:

// Initializing each mocks manually and use AutoFixture for the SUT
private ServicyMcServiceFace CreateFixtureSemiAuto()
{
    var fixture = new Fixture();

    var dep1 = new Mock<IDependency1>();

    fixture.Register(dep1.Object);

    return fixture.Create<ServicyMcServiceFace>();
}
Enter fullscreen mode Exit fullscreen mode

I did not gave muck attention to that method at the time, but recently I had to use it in a different manner so I decided to share it.
On the example above we have a service that have a service that has a dependency of type IDependency1. By registering the Mocked object with the fixture we're basically configuring it as our dependency injection (DI) container (or Inversion Of Control Container) and telling it to use that Mock every time someone asks for the IDependency1 interface. The same can be done with a real implementation of the interface, but instead of passing the mocked object we would pass a new instance of the implementing class.
So far so good.
But if we have a generic interface as our dependency that method overload will not work.

// Constructor for ServicyMcServiceFace
public ServicyMcServiceFace(IConverter<Type1, Type2> converter)
{ ... }

// The implementation or our dependency that we want to use on our test
public class T1toT2Converter: IConverter<Type1, Type2> { ... }
Enter fullscreen mode Exit fullscreen mode

On this example our SUT depends the a converter between Type1 and Type2, and we want to use the T1toT2Converter implementation of that interface on our tests (there are many reasons why one would prefer to do that instead of using a mock, but this discussion if beyond the point of this post). We can easily register that with in our fixture by using one of the generic overloads of the Register method as follows.

private ServicyMcServiceFace CreateFixtureSemiAuto()
{
    var fixture = new Fixture();

    // registering our interface implementation.
    fixture.Register<IConverter<Type1, Type2>>(() => new T1toT2Converter());

    return fixture.Create<ServicyMcServiceFace>();
}
Enter fullscreen mode Exit fullscreen mode

And there you go. Now every time you create a new instance of the SUT through the fixture it will receive a new instance of the converter.
If you want to use just one instance of the dependency you can just instantiate the dependency, save it to a field on your test suit and pass that in the Register callback method, for example.
The Register method is way more powerful than I make it appear here, and it gives a lot of options to customize how AutoFixture will generate your fixtures. I highly recommend reading the articles form Mark Seeman's blog that I'll add to the references at the end of this post.

So that's that for now, I hope this can be useful.


References:
Dealing With Types Without Public Constructors
Replacing AutoFixture's Default Algorithms

Discussion (0)