Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
277 views
in Technique[技术] by (71.8m points)

c# - AutoFixture - configure fixture to limit string generation length

When using AutoFixture's Build method for some type, how can I limit the length of the strings generated to fill that object's string properties/fields?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

With the Build method itself, there aren't that many options, but you can do something like this:

var constrainedText = 
    fixture.Create<string>().Substring(0, 10);
var mc = fixture
    .Build<MyClass>()
    .With(x => x.SomeText, constrainedText)
    .Create();

However, personally, I don't see how this is any better or easier to understand that this:

var mc = fixture
    .Build<MyClass>()
    .Without(x => x.SomeText)
    .Create();
mc.SomeText =
    fixture.Create<string>().Substring(0, 10);

Personally, I very rarely use the Build method, since I prefer a convention-based approach instead. Doing that, there are at least three ways to constrain string length.

The first option is just to constrain the base of all strings:

fixture.Customizations.Add(
    new StringGenerator(() =>
        Guid.NewGuid().ToString().Substring(0, 10)));
var mc = fixture.Create<MyClass>();

The above customization truncates all generated strings to 10 characters. However, since the default property assignment algorithm prepends the name of the property to the string, the end result will be that mc.SomeText will have a value like "SomeText3c12f144-5", so that is probably not what you want most of the time.

Another option is to use the [StringLength] attribute, as Nikos points out:

public class MyClass
{
    [StringLength(10)]
    public string SomeText { get; set; }
}

This means that you can just create an instance without explicitly stating anything about the property's length:

var mc = fixture.Create<MyClass>();

The third option I can think of is my favorite. This adds a specifically targeted convention that states that whenever the fixture is asked to create a value for a property with the name "SomeText" and of type string, the resulting string should be exactly 10 characters long:

public class SomeTextBuilder : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as PropertyInfo;
        if (pi != null && 
            pi.Name == "SomeText" &&
            pi.PropertyType == typeof(string))

            return context.Resolve(typeof(string))
                .ToString().Substring(0, 10);

        return new NoSpecimen();
    }
}

Usage:

fixture.Customizations.Add(new SomeTextBuilder());
var mc = fixture.Create<MyClass>();

The beauty of this approach is that it leaves the SUT alone and still doesn't affect any other string values.


You can generalize this SpecimenBuilder to any class and length, like so:

public class StringPropertyTruncateSpecimenBuilder<TEntity> : ISpecimenBuilder
{
    private readonly int _length;
    private readonly PropertyInfo _prop;

    public StringPropertyTruncateSpecimenBuilder(Expression<Func<TEntity, string>> getter, int length)
    {
        _length = length;
        _prop = (PropertyInfo)((MemberExpression)getter.Body).Member;
    }

    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as PropertyInfo;

        return pi != null && AreEquivalent(pi, _prop)
            ? context.Create<string>().Substring(0, _length)
            : (object) new NoSpecimen(request);
    }

    private bool AreEquivalent(PropertyInfo a, PropertyInfo b)
    {
        return a.DeclaringType == b.DeclaringType
               && a.Name == b.Name;
    }
}

Usage:

fixture.Customizations.Add(
    new StringPropertyTruncateSpecimenBuilder<Person>(p => p.Initials, 5));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...