g.pickardou
g.pickardou

Reputation: 35812

Customize AutoFixture property generation using constrained random values

Context

I would like to create a collection of my class, but some of its string property has constrained values. I would like to those values to be still random within the constrained set.

I figured out the customization way, but my the random generation implementation seems to be not using any AutoFixture feature, and I do not want to reinvent the wheel:

var random = new Random();
var fixture = new Fixture();
fixture.Customize<MyClass>(b => b
    .With(i => i.MyProperty, random.Next(2) == 0 ? "O" : "C"));

var result = fixture.CreateMany<MyClass>(1000);

Question

Is there any more efficient way to tell AutoFixture that I would like a random string "O" or "C"?

Edit

Meanwhile I realized that the code above does not work at all, so it do not qualify as "backup" plan. (The expression: random.Next(2) == 0 ? "O" : "C" evaluates only once)

Upvotes: 4

Views: 4432

Answers (2)

Coach David
Coach David

Reputation: 163

Using a lambda in your with statements will allow Autofixture to call your code each time it creates an object.

int totalPending = 0; int numberOfTotalEvents = 100; int numberOfStartingStatus = 10;string targetStatus = "Pending";string negativeTestStatus = "Failed";
var events = fixture. Build<Event>()
.With(specimenFound => specimenFound.Status, () =>
{
    string result = negativeTestStatus;

    if (totalPending < numberOfStartingStatus && Random.Shared.Next(0, 2) == 1)
    {
        result = targetStatus;
        totalPending++;
    }

    return result;
})          
.CreateMany(numberOfTotalEvents)
.ToList();

Upvotes: 0

Alex Povar
Alex Povar

Reputation: 734

Since AutoFixture 4.6.0 you can use callbacks inside the With customization function. That allows to constrain the field value, but let it still vary among the created specimens.

Example of source code:

[Fact]
public void CustomizeMany()
{
    var fixture = new Fixture();
    var items = fixture.Build<MyClass>()
        .With(x => x.EvenNumber, (int number) => number * 2)
        .CreateMany(1000)
        .ToArray();

    Assert.All(items, item => Assert.Equal(0, item.EvenNumber % 2));
}

public class MyClass
{
    public int EvenNumber { get; set; }
}

You can adjust the sample to meet your particular needs.

Upvotes: 8

Related Questions