AutoFixture是否可以从提供的数据集中生成随机字符串/文本? [英] Can AutoFixture generate random strings/text from a provided data set?

查看:114
本文介绍了AutoFixture是否可以从提供的数据集中生成随机字符串/文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

It is possible to use AutoFixture to generate random data for a string property .. but it's from a fixed data source?

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

For example: I have 30 street names hardcoded into a memory collection (array/list/whatever). Then, for my Address instance, the StreetName property isn't just a random string value (which is the default result from AutoFixture) but one of the street names from that hardcoded collection.

我的第一个想法是使用一个可能由AutoFixture创建的随机数。在数组的长度/大小内...因此,实际上我正在将数组插槽随机化。然后,使用该随机数,获取集合/数组槽的值(即街道名称)(即,给定索引器,获取该索引位置的值)。

My first thought was to use a random number which AutoFixture might be able to create.. and this number is inside the array length/size ... so in effect i'm randomizing an array slot. Then, using this random number, get the value (aka street name) of the collection/array slot (ie. given the indexer, get the value at that index location).

这应该怎么做?

推荐答案

与许多其他有关AutoFixture的事情一样,如果您遇到麻烦,事情会变得容易得多可以使用更明确的域建模 。与其将 StreetName 建模为 string ,而不是为其引入域对象:

As with so many other things regarding AutoFixture, things become much easier if you can use more explicit domain modelling. Instead of modelling StreetName as a string, introduce a domain object for it:

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);
    }
}

这是其中一个痛苦的建模步骤之一C#和Java,但在F#或Haskell中将是单线的。

This is one of those modelling steps that are painful in C# and Java, but would be a one-liner in F# or Haskell...

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

Let's assume, however, that we have a list of predefined street names:

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... */ };
}

您现在可以简单地告诉AutoFixture使用<$从该列表中进行选择c $ c> ElementsBuilder :

You can now trivially tell AutoFixture to pick only from that list, using ElementsBuilder:

var fixture = new Fixture();
fixture.Customizations.Add(
    new ElementsBuilder<StreetName>(StreetNames.Values.Select(s => (StreetName)s)));

不过,这意味着在创建 StreetName 值,它将从 StreetNames.Values 中选择,但是当您要求它创建<$ c时,它仍然不会这样做$ c>地址的值。您可以使用一些 ISpecimenBuilder 解决这个问题(哈哈):

At this point, though, it means that when you create StreetName values with AutoFixture, it'll pick from StreetNames.Values, but it still isn't going to do that when you ask it to create Address values. You can address (ha ha) that issue with a little 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;
    }
}

现在您可以配置夹具像这样:

Now you can configure your Fixture like this:

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

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

It'll now create Address values with StreetName values picked from the predefined list.

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

If you can't change your domain model, you can still add a class like StreetName. Just add it to your test code base instead of the production code base.

这篇关于AutoFixture是否可以从提供的数据集中生成随机字符串/文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆