Can AutoFixture generate random strings/text from a provided data set?

泄露秘密 提交于 2019-12-01 09:26:12

问题


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

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.

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).

Is this how it should be done?


回答1:


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

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

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

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

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

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.



来源:https://stackoverflow.com/questions/35261711/can-autofixture-generate-random-strings-text-from-a-provided-data-set

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!