Now that I've described how AutoFixture creates objects, it's time to look at a bit more advanced scenario. As you may recall, AutoFixture creates an object graph based on the public constructors of the types contained in that object graph.

That's all well and good when all involved types have public constructors, but what happens when this is not the case?

Imagine that the MyClass constructor has this signature:

public MyClass(IMyInterface mi)

Since IMyInterface is an interface it has no public constructors, so this will not work:

Fixture fixture = new Fixture();
MyClass sut = fixture.CreateAnonymous<MyClass>();

The second line of code will throw an ArgumentException ObjectCreationException* stating that “AutoFixture was unable to create an instance of type Ploeh.QualityTools.AutoFixtureDocumentationTest.Intermediate.IMyInterface, since it has no public constructor.” Not terribly surprising, actually.

To resolve this issue, the Register method allows you to specify a custom function that creates an object of the requested type. In the case of IMyInterface, that would be a Func<IMyInterface>:

Fixture fixture = new Fixture();
fixture.Register<IMyInterface>(() => 
    new FakeMyInterface());
MyClass sut = fixture.CreateAnonymous<MyClass>();

Here, I use a lambda expression to register the FakeMyInterface type, so that every time that particular Fixture instance is asked to create an instance of IMyInterface, it will invoke the lambda expression, and thus return an instance of FakeMyInterface (which obviously implements IMyInterface).

The Register method simply lets you map types without public constructors to concrete types created by a function you specify.

A more advanced scenario arises if you wish to use a specific text with this FakeMyInterface constructor overload:

public FakeMyInterface(int number, string text)

Obviously, you can do it manually like this:

Fixture fixture = new Fixture();
int anonymousNumber = fixture.CreateAnonymous<int>();
string knownText = "This text is not anonymous";
fixture.Register<IMyInterface>(() => 
    new FakeMyInterface(anonymousNumber, knownText));

Here, I simply use the fixture object to create an anonymous number, while the knownText variable is explicitly assigned a value, and then both are used as outer variables in the Register function.

This is, however, a common scenario, so the Register method has some convenience overloads that will supply anonymous input parameters for you to use or throw away as you like. This means that I can rewrite the above example to this:

Fixture fixture = new Fixture();
string knownText = "This text is not anonymous";
fixture.Register<int, string, IMyInterface>((i, s) => 
    new FakeMyInterface(i, knownText));

Compared to the previous example, I save a line of code. The drawback is that I have to explicitly specify the type parameters to the Register method. In my book, that's a pretty good tradeoff, as it removes a line of irrelevant code, and allows the test to focus on the relevant parts.

Notice that this Register overload creates both an anonymous integer and an anonymous string, but since I don't want to use the anonymous string (s), I just ignore it and use the knownText variable instead.

*Edit (2009-09-02): Changed the name of the Exception type to correctly reflect a breaking change introduced in AutoFixture .8.5.



Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or Google Plus, or somewhere else with a permalink. Ping me with the link, and I may add it as a comment.

Published

Thursday, 23 April 2009 19:51:42 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!