Search code examples
c#testingmockingautofixturebogus

Bogus, AutoFixture, others(?): How to fill a nested model with fake data and set rules for specific properties?


I have a very nested model that I want to create thousands of with fake data. But, also, some properties in the model need to be in a specific range or have specific rules. I looked at these two fake data generators:

AutoFixture only seems to generate fake data for everything.

Bogus can set rules like ranges for properties but all other properties remain null - or you have to define rules for all of them.

Did I miss something or is it not possible to fill the models with fake data and only set rules for specific properties?


Solution

  • AutoFixture enables you to establish rules for properties, either in a property-by-property basis, or by convention.

    Customise a specific property

    You can use Customize to change the behaviour for a particular type, including properties:

    [Fact]
    public void CustomizeSpecificProperty()
    {
        var fixture = new Fixture();
        fixture.Customize<MyClass>(c => c.With(mo => mo.Number, 42));
    
        var actual = fixture.Create<MyClass>();
    
        Assert.Equal(42, actual.Number);
    }
    

    This particular customization changes the rule for all MyClass.Number properties; the value will always be exactly 42.

    Customize by convention

    You can also match various properties by convention, often by looking at a combination of property type and name:

    [Fact]
    public void CustomizeTextPropertyByConvention()
    {
        var fixture = new Fixture();
        fixture.Customizations.Add(new TextPropertyBuilder());
    
        var actual = fixture.Create<MyClass>();
    
        Assert.Equal("Foo", actual.Text);
    }
    

    This option also requires that you write a custom TextPropertyBuilder class:

    public class TextPropertyBuilder : ISpecimenBuilder
    {
        public object Create(object request, ISpecimenContext context)
        {
            var pi = request as PropertyInfo;
            if (pi == null || pi.Name != "Text" || pi.PropertyType != typeof(string))
                return new NoSpecimen();
    
            return "Foo";
        }
    }
    

    This rule will apply to all string properties called "Text", no matter on which class they're defined.

    AutoFixture comes with a rich API that will enable you express many of such rules in a more succinct manner, but these are the main building blocks.


    Both the above examples use this MyClass:

    public class MyClass
    {
        public int Number { get; set; }
    
        public string Text { get; set; }
    }