How can I tell AutoFixture to always create TDerived when it instantiates a TBase?
Asked Answered
K

2

16

I have a deeply-nested object model, where some classes might look a bit like this:

class TBase { ... }

class TDerived : TBase { ... }

class Container
{
    ICollection<TBase> instances;
    ...
}

class TopLevel
{
    Container container1;
    Container container2;
    ...
}

I'd like to create my top-level object as a test fixture, but I want all the TBase instances (such as in the instances collection above) to be instances of TDerived rather than TBase.

I thought I could do this quite simply using something like:

var fixture = new Fixture();

fixture.Customize<TBase>(c => c.Create<TDerived>());

var model = this.fixture.Create<TopLevel>();

...but that doesn't work, because the lambda expression in Customize is wrong. I'm guessing there's a way to do this, but AutoFixture seems to lack documentation, other than as a stream-of-consciousness on the developer's blog.

Can anyone point me in the right direction?

Kokoschka answered 2/12, 2014 at 10:29 Comment(0)
E
14

While the answer by dcastro is also an option, the safest option is to use the TypeRelay class.

fixture.Customizations.Add(
    new TypeRelay(
        typeof(TBase),
        typeof(TDerived));
Eurhythmics answered 2/12, 2014 at 10:57 Comment(5)
Thanks. I do wish that was documented... :-)Kokoschka
It is: nudoq.org/#!/Packages/AutoFixture/Ploeh.AutoFixture/TypeRelay :)Eurhythmics
So, the "documentation" is: "Relays a request for the Type into a request for the Type", which doesn't actually make it sound that useful :-) But my wider point is that there's no way of finding even this scant information unless you either know where to look, or read through the whole API - it's like using a dictionary to look up a word you don't know how to spell. There needs to be a more complete tutorial or cheat-sheet, otherwise 99% of your potential user-base will be put off at the first hurdle, which would be a real shame, given the amount of effort that obviously went into it.Kokoschka
I hope I don't sound ungrateful - both for the answer, and the actual development of the library in the first place. I appreciate your time in both cases - I just think that a little more documentation might make a huge difference - and might mean you spend less time answering questions like this :-)Kokoschka
I'm not really arguing, and your point is well taken. That's the perpetual problem with OSS: no-one want to write documentation. AutoFixture does take pull requests, though :)Eurhythmics
S
9

Use the Register method to tell AutoFixture how to create instances of a particular type.

fixture.Register<TBase>(() => new TDerived());

or, as pointed out by @sgnsajgon :

fixture.Register<TBase>( fixture.Create<TDerived> );
Stanhope answered 2/12, 2014 at 10:42 Comment(4)
Also you can write: fixture.Register<TBase>( fixture.Create<TDerived> );Absurdity
@Absurdity Nice, I've added that to the answer :)Stanhope
Thanks, that worked. +1. However, it's hard to argue with Mark Seemann, so I've accepted his "more correct" answer.Kokoschka
@GaryMcGill You did the right thing, I didn't even know about TypeRelay :)Stanhope

© 2022 - 2024 — McMap. All rights reserved.