How can I instruct AutoFixture to not bother filling out some properties?
Asked Answered
M

2

41

I have a set of Data Access classes that are nested fairly deep.

To construct a list of 5 of them takes AutoFixture more than 2 minutes. 2 minutes per Unit test is way to long.

If I was coding them by hand, I would only code up the ones I need, so it would initialize quicker. Is there a way to tell AutoFixture to only do some of the properties so it can not spend time with areas of my structure I don't need?

For example:

public class OfficeBuilding
{
   public List<Office> Offices {get; set;}
}

public class Office
{
   public List<PhoneBook> YellowPages {get; set;}
   public List<PhoneBook> WhitePages {get; set;}
}

public class PhoneBook
{
    public List<Person> AllContacts {get; set;}
    public List<Person> LocalContacts {get; set;}
}

public class Person
{
   public int ID { get; set; }
   public string FirstName { get; set;}
   public string LastName { get; set;}
   public DateTime DateOfBirth { get; set; }
   public char Gender { get; set; }
   public List<Address> Addresses {get; set;}
}

public class Addresses
{
   public string Address1 { get; set; }
   public string Address2 { get; set; }
}

Is there a way to tell AutoFixture to create values for OfficeBuilding.Offices.YellowPages.LocalContacts, but not to bother with OfficeBuilding.Offices.YellowPages.AllContacts?

Maecenas answered 20/8, 2013 at 23:57 Comment(0)
H
22

One option is to create a Customization that omits properties of a certain name:

internal class PropertyNameOmitter : ISpecimenBuilder
{
    private readonly IEnumerable<string> names;

    internal PropertyNameOmitter(params string[] names)
    {
        this.names = names;
    }

    public object Create(object request, ISpecimenContext context)
    {
        var propInfo = request as PropertyInfo;
        if (propInfo != null && names.Contains(propInfo.Name))
            return new OmitSpecimen();

        return new NoSpecimen(request);
    }
}

You may use it as below:

var fixture = new Fixture();
fixture.Customizations.Add(
    new PropertyNameOmitter("AllContacts"));

var sut = fixture.Create<OfficeBuilding>();
// -> The 'AllContacts' property should be omitted now.

See also:

Hebdomadal answered 21/8, 2013 at 8:49 Comment(1)
Nowadays return new NoSpecimen(request); (obsolete) could be replaced with return new NoSpecimen();Lilalilac
T
59

The answer provided by Nikos Baxevanis provides various convention-based ways to answer the question. For completeness sake, you can also do a more ad-hoc build:

var phoneBook = fixture.Build<PhoneBook>().Without(p => p.AllContacts).Create();

If you want your Fixture instance to always do this, you can Customize it:

fixture.Customize<PhoneBook>(c => c.Without(p => p.AllContacts));

Every time that Fixture instance creates an instance of PhoneBook, it'll skip the AllContacts property, which means that you can go:

var sut = fixture.Create<OfficeBuilding>();

and the AllContacts property will remain untouched.

Trixy answered 23/8, 2013 at 12:24 Comment(0)
H
22

One option is to create a Customization that omits properties of a certain name:

internal class PropertyNameOmitter : ISpecimenBuilder
{
    private readonly IEnumerable<string> names;

    internal PropertyNameOmitter(params string[] names)
    {
        this.names = names;
    }

    public object Create(object request, ISpecimenContext context)
    {
        var propInfo = request as PropertyInfo;
        if (propInfo != null && names.Contains(propInfo.Name))
            return new OmitSpecimen();

        return new NoSpecimen(request);
    }
}

You may use it as below:

var fixture = new Fixture();
fixture.Customizations.Add(
    new PropertyNameOmitter("AllContacts"));

var sut = fixture.Create<OfficeBuilding>();
// -> The 'AllContacts' property should be omitted now.

See also:

Hebdomadal answered 21/8, 2013 at 8:49 Comment(1)
Nowadays return new NoSpecimen(request); (obsolete) could be replaced with return new NoSpecimen();Lilalilac

© 2022 - 2024 — McMap. All rights reserved.