Write 30% Less Test Code With AutoFixture
I have been following Mark Seemann for a while ‘cause this guy is as smart as it gets. He wrote a book on dependency injection, released two awesome courses on unit testing in Pluralsight, and has written the AutoFixture unit testing library (with many other contributors).
AutoFixture is a .NET library that helps you write unit tests with less code by providing:
- Test data generators for primitive and complex types (in a constrained non-deterministic way - the data generation algorithm can be customized)
- Test data builders for any type
- AutoMocking of dependencies
- I repeat, A U T O M O C K I N G of dependencies
and in words of Mark Seemann:
AutoFixture is an open source framework for .NET designed to minimize the ‘Arrange’ phase of your unit tests. Its primary goal is to allow developers to focus on what is being tested rather than how to setup the test scenario, by making it easier to create object graphs containing test data.
What does this means in terms of that application you are developing right now if you were to adopt AutoFixture just this very moment?
- Write less unit test code
- Bye writing mother objects
- Bye writing your own test data builders
- Bye to manually providing dependencies for your system under test
- But wait Joe! There’s more!
- By using a SUT (system under test) factory we effectively isolate all tests from changes in the SUT constructor. You will probably have handled this via factory methods, builders or fixture objects. But with AutoFixture and automocking, adding a new dependency to a constructor will not break any test!
- Being able to automock dependencies means that you don’t need to explicitly mock/stub dependencies that are not used in a given test, which in turns means that tests become more readable, intentional and deliberate. The code that it is there takes active part in the test. All crud is removed, gone, caput.
Installing AutoFixture
You can easily start using AutoFixture in your project via Nuaet:
>Install-Package AutoFixture
>Install-Package AutoFixture.NUnit2
>Install-Package AutoFixture.AutoRhinoMock
Note: I am using Nunit and RhinoMocks in this article but there is support for many other testing frameworks and mocking libraries.
Where each of these packages consist in the following:
- AutoFixture: this is AutoFixture itself
- AutoFixture.NUnit2: this is an improved integration between AutoFixture and NUnit that allows AutoFixture to inject test data and SUT directly in NUnit Test methods
- AutoFixture.AutoRhinoMock: this allows auto mocking of dependencies via Rhino.Mocks
Using AutoFixture
I am going to go fast like lightning through some of the interesting features provided by AutoFixture, brace yourself:
Auto Mocking SUT Dependencies
public class Calculator{
private readonly ILogger logger;
private readonly IEmailSender emailSender;
private readonly IArgumentParser argumentParser;
private readonly IBellsAndWistles bellsAndWistles;
public Calculator(ILogger logger, IArgumentParser argumentParser, IEmailSender emailSender, IBellsAndWistles bellsAndWistles){...}
public int Add(string arguments){
Tuple<int,int> operands = argumentParser.Parse(arguments)
var sum = operands.Item1 + operands.Item2;
logger.Info(string.Format("I just added a couple of numbers {0} + {1} = {2}", operands.Item1, operands.Item2, sum));
emailSender.Send(new AdditionWasDoneNotificationEmail(operands, sum));
bellsAndWistles.Alarm(operands, sum);
return sum;
}
}
[TestFixture]
public class CalculatorTests{
private IFixture fixture;
[SetUp]
public void SetUp(){
fixture = new Fixture().Customize(new AutoRhinoMockCustomization());
}
[TestCase("1 1",1,1,2)]
[TestCase("2 2",2,2,4)]
[TestCase("3 2",3,2,5)]
public void AddTwoIntegers_ShouldPerformAddition(string arguments, int op1, int op2, int expectedSum)
{
// Arrange
var argumentParser = fixture.Freeze<IArgumentParser>();
argumentParser.Stub(p => p.Parse(arguments)).Return(new Tuple<int,int>(op1, op2));
var calculator = fixture.Create<Calculator>();
// Act
var sum = calculator.Add(arguments);
// Assert
Assert.That(sum, Is.EqualTo(expectedSum));
}
// more tests
}
###Test Builders For Any Type
var camilla = fixture.Build<User>()
.With(u => u.FirstName, "Camilla")
.With(u => u.SecondName, "For Great Justice")
.Without(u => u.Roles)
.Without(u => u.ParentCompany)
Create(); // other fields filled with data generated
###Generating Test Data
// for complex types
var camilla = fixture.Create<User>(); // all fields are filled with data generated
// for primitive types
var number = fixture.Create<int>();
Note For The Intrepid: AutoFixture doesn’t work well if there are cycles in the object graph. If a complex type has cycles, you will need to tell AutoFixture to leave that property alone (OmitAutoProperties
) or set it explicitely.
Integration with NUnit
If we do a full integration with NUnit we can remove the Arrange stage and inject the test data directly as arguments:
[Test, AutoData]
public void IntroductoryTest(int expectedNumber, MyClass sut)
{
// Act
int result = sut.Echo(expectedNumber);
// Assert
Assert.Equal(expectedNumber, result);
}
And even auto mock SUT dependencies:
[Test, AutoData]
[AutoRhinoMockData]
public void IntroductoryTest(int expectedNumber, MyClass sut)
{
// Act
int result = sut.Echo(expectedNumber);
// Assert
Assert.Equal(expectedNumber, result);
}
// in this case you need to define a new attribute
internal class AutoRhinoMockDataAttribute : AutoDataAttribute
{
internal AutoRhinoMockDataAttribute() : base(new Fixture().Customize(new AutoRhinoMockCustomization())){}
}
Mind Officially Blown Away. Booom… Boooom… Booom… Boooom… Booooom…
It even has testimonials. Open-source library with testimonials?!? Whatz?!?:
“I’ve introduced AutoFixture to my developers (at www.gab.de ) some time ago. We’ve been using it successfully with xunit in multiple projects all across the .NET technology stack. We also use it for feeding dummy data to the UI when developing prototypes. That saved us quite some time. Florian Hötzinger, GAB Enterprise IT Solutions GmbH
“I have used AutoFixture for 3 years, it’s a vital tool in my TDD toolbox, a real time-saver. Setting up maintainable and robust unit tests with AutoFixture is easy and straightforward - highly recommendable” Mads Tjørnelund Toustrup, Senior .Net Developer
“Autofixture is more than just another test data generator. It helps me to write tests faster, which are robust against changes in my production code. Moreover, with Autofixture I can focus the tests on the behavior I want to check which why they are easier to read and understand.” Hendrik Lösch, Saxonia Systems AG
It is time to Experiment Thyselve! Go NuGet Install-Package AutoFixture
Now!
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.