AutoFixture可以构建具有唯一属性的集合。

7
有没有可能在AutoFixture中创建一个具有唯一属性的集合?例如,我想创建一个包含以下内容的集合:
public class Foo {
 public int Id {get; set;}
 public string Name {get;set;}
}

带有唯一的Id。它大致看起来像这样:

var fixture = new Fixture();

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

我知道可以通过自定义来实现这一点,但我认为这是相当普遍的场景,AutoFixture可能已经准备好了相关内容吗?

1个回答

10

Autofixture默认为属性生成唯一值。因此,您不必指定哪个属性应该是唯一的 - 反之,请为其他属性指定非唯一值:

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

请注意,如果您想确保其他属性的非唯一值(仅具有Id唯一),则可以创建简单的扩展IPostprocessComposer,为该属性提供可能的值集合。
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)]);
}

使用很简单 - 下面的代码创建了一个foo列表,仅使用两个不同的名称值和三个不同的整数属性值:

fixture.Build<Foo>()
    .With(f => f.SomeIntegerProperty, 10, 20, 50)
    .With(f => f.Name, fixture.CreateMany<string>(2))
    .CreateMany(20);

所以,除非您在 byte 类型的集合中超过了255个元素,否则它始终是唯一的? - OlegI
@OlegI 是的,有使用RandomNumericSequencegenerator,它可以创建一个从1开始的随机、唯一数字序列(仅跟踪已返回范围内的随机数列表)。在范围内的所有数字都被返回后,历史记录将被清除,并重新开始生成。 - Sergey Berezovskiy
1
@OlegI 你可以在这里检查数字生成器的代码 [https://github.com/AutoFixture/AutoFixture/blob/master/Src/AutoFixture/RandomNumericSequenceGenerator.cs] - Sergey Berezovskiy
实际上,在超出byte范围之后,RandomNumericSequenceGenerator会切换到更大的范围,不包括先前的范围。因此,如果您的属性足够宽(例如shortint),我会说数字始终是唯一的。 - Alex Povar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接