AutoFixture 可以从提供的数据集中生成随机字符串/文本吗?

Pur*_*ome 6 .net c# autofixture

可以使用 AutoFixture 为字符串属性生成随机数据..但它来自固定数据源?

例如:我有 30 个街道名称硬编码到内存集合(数组/列表/其他)中。然后,对于我的Address实例,该StreetName属性不仅仅是一个随机字符串值(这是 AutoFixture 的默认结果),而且是该硬编码集合中的街道名称之一。

我的第一个想法是使用 AutoFixture 可能能够创建的随机数..并且该数字位于数组长度/大小内...所以实际上我正在随机化数组槽。然后,使用这个随机数,获取集合/数组槽的值(也称为街道名称)(即给定索引器,获取该索引位置的值)。

这是应该做的吗?

Mar*_*ann 5

与 AutoFixture 相关的许多其他事情一样,如果您可以使用更明确的域建模,事情就会变得容易得多。不要建模StreetNamestring,而是为其引入一个域对象:

public sealed class StreetName
{
    private readonly string value;

    public StreetName(string streetName)
    {
        value = streetName ?? throw new ArgumentNullException(nameof(streetName));
    }

    public override bool Equals(object obj)
    {
        var other = obj as StreetName;
        if (other == null)
            return base.Equals(obj);

        return Equals(value, other.value);
    }

    public override int GetHashCode()
    {
        return value.GetHashCode();
    }

    public override string ToString()
    {
        return value;
    }

    public static implicit operator string(StreetName streetAddress)
    {
        return streetAddress.value;
    }

    public static implicit operator StreetName(string streetAddress)
    {
        return new StreetName(streetAddress);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是在 C# 和 Java 中令人痛苦的建模步骤之一,但在 F# 或 Haskell 中却是一句简单的话……

但是,假设我们有一个预定义的街道名称列表:

public static class StreetNames
{
    public static IEnumerable<string> Values = new[] {
        "221 B Baker St.",
        "1313 Webfoot Walk",
        "420 Paper St.",
        "42 Wallaby Way"
        /* More addresses go here... */ };
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以简单地告诉 AutoFixture 仅从该列表中进行选择,使用ElementsBuilder

var fixture = new Fixture();
fixture.Customizations.Add(
    new ElementsBuilder<StreetName>(StreetNames.Values.Select(s => (StreetName)s)));
Run Code Online (Sandbox Code Playgroud)

不过,此时,这意味着当您StreetName使用 AutoFixture 创建值时,它会从 中进行选择StreetNames.Values,但当您要求它创建值时,它仍然不会这样做Address。你可以用一点点来解决(哈哈)这个问题ISpecimenBuilder

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

        var sn = context.Resolve(typeof(StreetName));
        return (string)(StreetName)sn;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以Fixture这样配置:

var fixture = new Fixture();
fixture.Customizations.Add(
    new ElementsBuilder<StreetName>(StreetNames.Values.Select(s => (StreetName)s)));
fixture.Customizations.Add(new StreetNameBuilder());
Run Code Online (Sandbox Code Playgroud)

现在,它将使用从预定义列表中选取的值Address来创建值。StreetName

如果您无法更改域模型,您仍然可以添加一个类,例如StreetName. 只需将其添加到您的测试代码库而不是生产代码库中即可。

  • 为什么不能只添加一个名为 `One.Of(new {"Buy","Sell"})` 或 `One.Of(params object[] string` 的函数,这样它就只是 `One.Of("Buy" ","Sell")` 或 `One.Of(Enumerable.Range(1, 50))` ?我认为您的答案对于用户的要求来说过于复杂,并且用户为您提供了关于如何制作的好主意AutoFixture 更容易使用。通常,我们希望集合由以下一个或多个组合构建:最多一个元素是特定值,所有元素都是唯一的,所有元素都是其他元素集的子集,所有元素都是唯一子-其他一些元素的集合,等等...... (2认同)
  • 感谢您的及时回复。完毕。https://github.com/AutoFixture/AutoFixture/issues/1179 (2认同)