Mapping types with AutoFixture by Mark Seemann
In my previous posts I demonstrated interaction-based unit tests that verify that a pizza is correctly being added to a shopping basket. An alternative is a state-based test where we examine the contents of the shopping basket after exercising the SUT. Here's an initial attempt:
[TestMethod] public void AddWillAddToBasket() { // Fixture setup var fixture = new Fixture(); fixture.Register<IPizzaMap>( fixture.CreateAnonymous<PizzaMap>); var basket = fixture.Freeze<Basket>(); var pizza = fixture.CreateAnonymous<PizzaPresenter>(); var sut = fixture.CreateAnonymous<BasketPresenter>(); // Exercise system sut.Add(pizza); // Verify outcome Assert.IsTrue(basket.Pizze.Any(p => p.Name == pizza.Name), "Basket has added pizza."); // Teardown }
In this case the assertion examines the Pizze collection (you did know that the plural of pizza is pizze, right?) of the frozen Basket to verify that it contains the added pizza.
The tricky part is that the Pizze property is a collection of Pizza instances, and not PizzaPresenter instances. The injected IPizzaMap instance is responsible for mapping from PizzaPresenter to Pizza, but since we are rewriting this as a state-based test, I thought it would also be interesting to write the test without using Moq. Instead, we can use the real implementation of IPizzaMap, but this means that we must instruct AutoFixture to map from the abstract IPizzaMap to the concrete PizzaMap.
We see that happening in this line of code:
fixture.Register<IPizzaMap>( fixture.CreateAnonymous<PizzaMap>);
Notice the method group syntax: we pass in a delegate to the CreateAnonymous method, which means that every time the fixture is asked to create an IPizzaMap instance, it invokes CreateAnonymous<PIzzaMap>() and uses the result.
This is, obviously, a general-purpose way in which we can map compatible types, so we can write an extension method like this one:
public static void Register<TAbstract, TConcrete>( this Fixture fixture) where TConcrete : TAbstract { fixture.Register<TAbstract>(() => fixture.CreateAnonymous<TConcrete>()); }
(I'm slightly undecided on the name of this method. Map might be a better name, but I just like the equivalence to some common DI Containers and their Register methods.) Armed with this Register overload, we can now rewrite the previous Register statement like this:
fixture.Register<IPizzaMap, PizzaMap>();
It's the same amount of code lines, but I find it slightly more succinct and communicative.
The real point of this blog post, however, is that you can map abstract types to concrete types, and that you can always write extension methods to encapsulate your own AutoFixture idioms.
Comments