DEV Community

loading...

TIL: Using AutoFixture with auto mocking is awesome.

pedrostc profile image Pedro Osternack Corrêa ・2 min read

I'm working on a .net core project and going through the tests I got my first contact with AutoFixture which is a tool that can ...create values of virtually any type without the need for you to explicitly define which values should be used. So it can help with the creation of mock data (the main use I was aware of so far) and test doubles, making life a bit easier.

Today I've found out that it has an integration with the mocking library we're using, Moq that makes it work as a DI container that provides mocks of dependencies for your classes.

ex.:

// Initializing each mocks and the SUT by hand
private ServicyMcServiceFace CreateFixtureFullManual()
{
    var dep1 = new Mock<IDependency1>();
    var dep2 = new Mock<IDependency2>();
    var dep3 = new Mock<IDependency3>();

    return new ServicyMcServiceFace(dep1.Object, dep2.Object, dep3.Object);
}

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

    var dep1 = new Mock<IDependency1>();
    var dep2 = new Mock<IDependency2>();
    var dep3 = new Mock<IDependency3>();

    fixture.Register(dep1.Object);
    fixture.Register(dep2.Object);
    fixture.Register(dep3.Object);

    return fixture.Create<ServicyMcServiceFace>();
}

// Going full auto with AutoFixture.AutoMoq
private ServicyMcServiceFace CreateFixtureFullAuto()
{
    // We configure the Fixture to use the necessary customization
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    return fixture.Create<ServicyMcServiceFace>();
} 
Enter fullscreen mode Exit fullscreen mode

As we can see above the SUT initialization became way simpler since we don't need to initialize each dependency by hand.

Now, what if we want to specify a behaviour for one of our mocks? Well, we can do that by using the freeze method of our fixture.

ex.:

[Test]
public void DoTheThing_Dep1ReturnsNegativeNumber_SignalsThatNegativeWasReceived()
{
    // Initializing the fixture object with the AutoMoq Customization
    var fixture = new Fixture().Customize(new AutoMoqCustomization());

    // Freezes the instance of the IDependency1 Mock that will be used in this scope.
    // With it we can set up the Mock and it will be used on the instantiation of our SUT later on.
    fixture.Freeze<Mock<IDependency1>>().Setup(d => d.GetAnswer(), -42);

    // The created object will receive the mock as we set up previously
    var sut = fixture.Create<ServicyMcServiceFace>();
    sut.DoTheThing();

    Assert.True(sut.GotNegativeAnswer);
}
Enter fullscreen mode Exit fullscreen mode

Awesome right? It makes life way simpler, mainly with you're dealing with Classes with tons of dependencies. I feel that the ability to use AutoFixture to manage all dependencies and only really get what you need when you need is a very powerful one and can make tests way simpler and a bit cleaner by removing a good amount of code from the setup step.

Hope this can be helpful to someone else.
Cheers.

Some sources:
Freezing mocks by Mark Seemann
AutoFixture as an auto-mocking container by Mark Seemann

Discussion (1)

Collapse
raffernandes profile image
Rafael Fernandes

Good stuff. Thanks for sharing!

Forem Open with the Forem app