AutoFixture As Fixture Object by Mark Seemann
Dear reader, I hope you are still with me!
After eight posts of AutoFixture feature walkthroughs, I can't blame you for wondering why this tool might even be relevant to you. In this post, we'll finally begin to look at how AutoFixture can help you towards Zero-Friction TDD!
In an earlier post, I described how the Fixture Object pattern can help you greatly reduce the amount of test code that you have to write. Since AutoFixture was designed to act as a general-purpose Fixture Object, it can help you reduce the amount of test code even further, letting you focus on specifying the behavior of your SUT.
In that former post, the original example was this complex test that I will repeat in it's entirety for your benefit (or horror):
[TestMethod] public void NumberSumIsCorrect_Naïve() { // Fixture setup Thing thing1 = new Thing() { Number = 3, Text = "Anonymous text 1" }; Thing thing2 = new Thing() { Number = 6, Text = "Anonymous text 2" }; Thing thing3 = new Thing() { Number = 1, Text = "Anonymous text 3" }; int expectedSum = new[] { thing1, thing2, thing3 }. Select(t => t.Number).Sum(); IMyInterface fake = new FakeMyInterface(); fake.AddThing(thing1); fake.AddThing(thing2); fake.AddThing(thing3); MyClass sut = new MyClass(fake); // Exercise system int result = sut.CalculateSumOfThings(); // Verify outcome Assert.AreEqual<int>(expectedSum, result, "Sum of things"); // Teardown }
This test consists of 18 lines of code.
Using the Fixture Object pattern, I was able to cut that down to 7 lines of code, which is a 61% improvement (however, the downside was an additional 19 lines of (reusable) code for MyClassFixture, so the benefit can only be reaped when you have multiple tests leveraged by the same Fixture Object. This was all covered in the former post, to which I will refer you).
With AutoFixture, we can do much better. Here's a one-off rewrite of the unit test using AutoFixture:
[TestMethod] public void NumberSumIsCorrect_AutoFixture() { // Fixture setup Fixture fixture = new Fixture(); IMyInterface fake = new FakeMyInterface(); fixture.Register<IMyInterface>(() => fake); var things = fixture.CreateMany<Thing>().ToList(); things.ForEach(t => fake.AddThing(t)); int expectedSum = things.Select(t => t.Number).Sum(); MyClass sut = fixture.CreateAnonymous<MyClass>(); // Exercise system int result = sut.CalculateSumOfThings(); // Verify outcome Assert.AreEqual<int>(expectedSum, result, "Sum of things"); // Teardown }
In this test, I map the concrete fake instance to the IMyInterface type in the fixture object, and then use its ability to create many anonymous instances with one method call. Before exercising the SUT, I also use the fixture instance as a SUT Factory.
Apart from AutoFixture (and FakeMyInterface, which is invariant for all variations, and thus kept out of the comparison), this test stands alone, but still manages to reduce the number of code lines to 10 lines - a 44% improvement! In my book, that's already a significant gain in productivity and maintainability, but we can do better!
If we need to test MyClass repeatedly in similar ways, we can move the common code to a Fixture Object based on AutoFixture, and the test can be refactored to this:
[TestMethod] public void NumberSumIsCorrect_DerivedFixture() { // Fixture setup MyClassFixture fixture = new MyClassFixture(); fixture.AddManyTo(fixture.Things); int expectedSum = fixture.Things.Select(t => t.Number).Sum(); MyClass sut = fixture.CreateAnonymous<MyClass>(); // Exercise system int result = sut.CalculateSumOfThings(); // Verify outcome Assert.AreEqual<int>(expectedSum, result, "Sum of things"); // Teardown }
Now we are back at 7 lines of code, which is on par with the original Fixture Object-based test, but now MyClassFixture is reduced to 8 lines of code:
internal class MyClassFixture : Fixture { internal MyClassFixture() { this.Things = new List<Thing>(); this.Register<IMyInterface>(() => { var fake = new FakeMyInterface(); this.Things.ToList().ForEach(t => fake.AddThing(t)); return fake; }); } internal IList<Thing> Things { get; private set; } }
Notice how I've moved the IMyInterface-to-FakeMyInterface mapping to MyClassFixture. Whenever it's asked to create a new instance of IMyInterface, MyClassFixture makes sure to add all the Thing instances to the fake before returning it.
Compared to the former Fixture Object of 19 lines, that's another 58% improvement. Considering some of the APIs I encounter in my daily work, the above example is even rather simple. The more complex and demanding your SUT's API is, the greater the gain from using AutoFixture will be, since it's going to figure out much of the routine stuff for you.
With this post, I hope I have given you a taste of the power that AutoFixture provides. It allows you to focus on specifying the behavior of your SUT, while taking care of all the infrastructure tedium that tends to get in the way.