AutoFixture build collection with unique property
Asked Answered
R

1

9

Is there any possibility to create a collection with a unique property in AutoFixture? For instance, I would like to create a collection of:

public class Foo {
 public int Id {get; set;}
 public string Name {get;set;}
}

with unique Id. It would look something like this:

var fixture = new Fixture();

fixture
 .Build<Foo>()
 .WithUnique((foo) => foo.Id)
 .CreateMany(20);

I know it is possible to do this through customization, but I think it's quite common scenario so might be AutoFixture has something ready for this?

Representative answered 26/3, 2019 at 15:42 Comment(0)
C
12

Autofixture by default generates unique values for properties. So you don't have to specify which property should be unique - instead, specify a non-unique value for other property:

// with AutoFixture.SeedExtensions
fixture.Build<Foo>().With(f => f.Name, fixture.Create("Name")).CreateMany(20)

Note if you want to ensure non-unique values for other properties (having only Id unique), then you can create simple extensions for IPostprocessComposer which provide a set of possible values for the property:

public static IPostprocessComposer<T> With<T, TProperty>(
    this IPostprocessComposer<T> composer,
    Expression<Func<T, TProperty>> propertyPicker,
    IEnumerable<TProperty> possibleValues) =>
      composer.With(propertyPicker, possibleValues.ToArray());

public static IPostprocessComposer<T> With<T, TProperty>(
    this IPostprocessComposer<T> composer,
    Expression<Func<T, TProperty>> propertyPicker,
    params TProperty[] possibleValues)
{
    var rnd = new Random();
    return composer.With(
       propertyPicker,
       () => possibleValues[rnd.Next(0, possibleValues.Length)]);
}

Usage is simple - following code creates list of foos with only two different values for name, and three different values for some integer property:

fixture.Build<Foo>()
    .With(f => f.SomeIntegerProperty, 10, 20, 50)
    .With(f => f.Name, fixture.CreateMany<string>(2))
    .CreateMany(20);
Canny answered 26/3, 2019 at 15:59 Comment(4)
So it's always unique unless you exceed for instance 255 elements in the collection for byte type?Representative
@Representative yes, there is RandomNumericSequencegenerator used which Creates a sequence of random, unique, numbers starting at 1. (it just tracks list of random numbers in the range which already returned). After all numbers from range returned, history is cleared and generation starts from scratchCanny
@Representative you can check the numbers generation hereCanny
@SergeyBerezovskiy Actually, after the byte range is exceeded, the RandomNumericSequenceGenerator switches to the larger range, which doesn't include the previous range. Therefore, I'd say that numbers are always unique, if your property is of wide enough type (e.g. short or int).Calci

© 2022 - 2024 — McMap. All rights reserved.