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

2

13

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?

Reviewer answered 12/1, 2018 at 11:47 Comment(0)
S
6

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; }
}
Scopp answered 12/1, 2018 at 12:24 Comment(2)
Using fixture.Create<MyClass>(); in the first example, will all other properties in the class also have contents?Reviewer
@Reviewer Yes github.com/AutoFixture/AutoFixture/wiki/…Scopp
A
17

Bogus has a community extension called AutoBogus written by Nick Dodd that lets you auto-generate rules for your models.

You can also override auto-generated rules that AutoBogus created with specific values for specific tests. Check out the AutoBogus readme for more info.

Also, you don't have to choose one or the other. You can use both. Bogus has a Faker class (not Faker<T>) that you can use without a fluent setup and without having to define a model T. The Faker class gives you access to all the datasets for realistic data generation. So, you can use Bogus' Faker object in combination with AutoFixture's conventions. :)

Hope that helps!
Brian

Antlion answered 15/5, 2018 at 19:54 Comment(0)
S
6

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; }
}
Scopp answered 12/1, 2018 at 12:24 Comment(2)
Using fixture.Create<MyClass>(); in the first example, will all other properties in the class also have contents?Reviewer
@Reviewer Yes github.com/AutoFixture/AutoFixture/wiki/…Scopp

© 2022 - 2024 — McMap. All rights reserved.