Dependency injection in unit tests: Introducing Autofixture

Please let someone else take care of that.

Changing dependencies in your SUT (system under test) usually means that you have to revise all of your previous tests. This is because the default way of instantiating your SUT is newing one up and passing in any mocks it might need. This destroys test and code maintainability. Every time you make a change to your constructor, you have to revisit all test cases and rewrite them. It does not matter whether or not that new dependency is part of your test. Wouldn’t it be nice to be able to use dependency injection in unit tests?

Well this is in fact possible with Autofixture. Autofixture is a testing framework created by Mark Seemann, author of “Dependency Injection: Principles, Practices, Patterns”. He is was also part of the team that developed F#! This guy is crazy smart, and really interesting to listen to. If you ever have some time to kill, go ahead and listen to some talks he’s made, it’s very easy to find him on YouTube. Anyway, let me take my fanboy hat off and get started.

What is Autofixture?

Autofixture is a framework developed in order to minimize the amount of work needed during the setup/arrange phase of a test. Not only that, but it also makes them much more maintainable. It does so mainly in two ways:

  • By taking responsibility for creating your SUT
  • By providing a generic Test Data Builder

Why is this so powerful? Because you no longer need to care about how your object is created and/or what parameters are sent into it! The framework makes it feel as if you are actually using dependency injection in unit tests.

How to use it?

It’s really, really simple. First, you register whatever classes you might need in your tests, and then you request the actual SUT from the fixture. Here, let me show you:

class TestClass
{
    private readonly IFace face;
    public TestClass(IFace iFace) => this.face = iFace;
    public bool IsFaceEmpty() => face == null;
}

[Fact]
public void Test_For_Dependency()
{
    var fixture = new Fixture();

    var faceMock = new Mock<IFace>();

    // ... setup the face mock

    fixture.Register(() => faceMock.Object);

    var sut = fixture.Create<TestClass>();

    Assert.False(sut.IsFaceEmpty());
}

Just like with a dependency injection container, you have to create the object graph. There is one big difference though: the object graph here tends to be really shallow. There is usually just your SUT and whatever dependencies it might need, as mocks. And mocks don’t have dependencies.

This doesn’t solve the original problem though; if I change the constructor, the test will fail since it doesn’t know what to do with the dependency and can’t resolve it. The last piece of the puzzle is Autofixture.Automoq, or whatever other mocking framework you use.

As an example, you usually don’t care how your logger interacts with most of your application. You have a few tests, making sure that the logger is actually called, but other than that, it’s getting on your nerves that you have to create and register it for every single test. Have a look at this:

class LoggerDependent
{
    private readonly ILogger logger;
    public LoggerDependent(ILogger logger) => this.logger = logger;

    public bool Log(string message) 
    {
        logger?.Information(message);
        return logger == null;
    }
}

[Fact]
public void Test_For_Logger_Dependency()
{
    var fixture = new Fixture();
    fixture.Customize(new AutoMoqCustomization());

    var anonMessage = fixture.Create<string>();
    var sut = fixture.Create<LoggerDependent>();

    Assert.False(sut.Log(anonMessage));
}

Honestly, I think this is so powerful that you would be crazy not to use this. You can even have the fixture create objects with random values, just like in line 21. If you need to control the mock, you can do the following:

var faceMock = fixture.Freeze<Mock<IFace>>();
faceMock.Setup(x => x.IsHappy()).Returns(true);

By using Freeze(), you are telling Autofixture to use the instance that it just created for you any other place the object graph calls for a IFace.

But wait, I froze a Mock<IFace> and not a IFace?! Well, Autofixture don’t give a damn, it knows what a mock is and it knows it should grab the proxy object for you instead of the mock itself. Which is awesome.

Conclusion

I hope that you can see how this makes it so much easier to write and maintain tests. By no longer needing to manage how the class is constructed, you can now change the constructor at will, without having to revisit all your tests every time you do so. Not only that, you no longer need to take into account any dependencies that are not part of your tests. Your tests are much more targeted.

I know that I mentioned that Autofixture also brings a test data builder, but this article got a bit longer than I expected. That will be covered in another article. I will also show you how to use Autofixture with xUnit. This will allow you to pass the entire fixture through test parameters.

I hope you enjoyed the article! Stay tuned for more!

1 thought on “Dependency injection in unit tests: Introducing Autofixture

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.