How to use AutoFixture to generate specific values when the Builder is given an abstract class
Asked Answered
E

1

8

I'm trying to generate specific values for a class with AutoFixture but the Builder is given an abstract class. As such, the builder can't see the properties for either concrete types ... and therefore cannot/doesn't know when/how to create them.

e.g.

public abstract class BaseClass
{
    // Common properties.
    public string Id { get; set }
    public Baa Baa { get; set; }
}

public class ConcreteA : BaseClass
{
    public string Name { get; set ;}
}

public class ConcreteB : BaseClass
{
    public NumberOfPeople int { get; set }
}

So, when I create a fake instance of a BaseClass, I'm hoping to set the concrete value, where appropriate.

e.g.

Class      | Property and value, to set.
----------------------------------------
ConcreteA  | Name = "Jane"
ConcreteB  | NumberOfPeople = 3

I'm not sure how to define (in the Builder) that when currentType == typeof(ConcreteA) then do this... etc.

Update

This is how I am currently creating my fake instances:

public static T CreateAThing<T>() where T : BaseClass, new()
{
    var fixture = new Fixture();
    return fixture.Build<T>()
        .With(x => x.Id, $"things-{fixture.Create<int>()}")
        .Create();
}

where the Id is a consecutive number appended to some fixed string.

Now, when T is a ConcreteA, then I was hoping to have it do some specific logic. (like set the name to be some first name + surname) while if T is a ConcreteB, then some random number from 1 to 10.

NOTE: The reason I was doing it like this, was because I was just thinking about not repeating myself for the baseclass properties (like how I'm wanting the Id property to be things-<consecutive number>.

Open to all ideas :)

Edrisedrock answered 5/2, 2016 at 3:42 Comment(4)
Given that you're asking to create an instance of a base object, how would it be possible to get instances of derived objects filled in as well?Aquino
What's wrong with fixture.Create<ConcreteA>() and fixture.Create<ConcreteB>()?Semitics
Possible duplicate: https://mcmap.net/q/729006/-how-can-i-tell-autofixture-to-always-create-tderived-when-it-instantiates-a-tbase/126014Semitics
Updated OP with an example about how i'm using Autofixture to create my concrete's.Edrisedrock
S
12

You can customize each concrete type individually:

fixture.Customize<ConcreteA>(c => c.With(x => x.Name, "Jane"));
fixture.Customize<ConcreteB>(c => c.With(x => x.NumberOfPeople, 3));

Subsequently, you can simply create them:

var a = fixture.Create<ConcreteA>();
var b = fixture.Create<ConcreteB>();

Console.WriteLine(a.Name);
Console.WriteLine(b.NumberOfPeople);

Prints:

Jane
3
Semitics answered 5/2, 2016 at 13:12 Comment(2)
Gotcha -- or use ICustomization along with CompositeCustomization if i wish to reuse these cusomized concretes in multiple tests, right?Edrisedrock
@Edrisedrock Correct. This answer, however, doesn't provide any information on how to translate a base class into a concrete class, but if you need that, then this answer explains how to do that.Semitics

© 2022 - 2024 — McMap. All rights reserved.