How to configure AutoFixture to use an enum value as seed when creating many of a certain type?

霸气de小男生 提交于 2019-12-05 06:09:07

You could do this:

var users = new Fixture().Create<Generator<User>>();

var onlineUser = users.Where(u => u.Status == Status.Online).First();
var offlineUser = users.Where(u => u.Status == Status.Offline).First();

If you're using AutoFixture.Xunit, the declarative equivalent is:

[Theory, AutoData]
public void CreateOneOfEachDeclaratively(Generator<User> users)
{
    var onlineUser = users.Where(u => u.Status == Status.Online).First();
    var offlineUser = users.Where(u => u.Status == Status.Offline).First();

    // Use onlineUser and offlineUser here...
}
Daniel Hilgarth

Based on Mark's answer, this is what I am using now:

fixture.Customize<User>(c => c.Without(x => x.Status));
fixture.Customize<IEnumerable<User>>(
    c =>
    c.FromFactory(
        () => Enum.GetValues(typeof(Status)).Cast<Status>()
                  .Select(s => users.First(u => u.Status == s))));

fixture.Create<IEnumerable<User>>(); // returns two Users

You may declare and use a customization, e.g. StatusGenerator:

var fixture = new Fixture();
fixture.RepeatCount = 2;
fixture.Customizations.Add(new StatusGenerator());

var result = fixture.CreateMany<User>();

A hypothetical implementation of the StatusGenerator could be the following:

internal class StatusGenerator : ISpecimenBuilder
{
    private readonly Status[] values;
    private int i;

    internal StatusGenerator()
    {
        this.values =
            Enum.GetValues(typeof(Status)).Cast<Status>().ToArray();
    }

    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as ParameterInfo;
        if (pi == null || !pi.ParameterType.IsEnum)
            return new NoSpecimen(request);

        return this.values[i == this.values.Length - 1 ? i = 0 : ++i];
    }
}

I know it is already answered and the Generator was a very interesting finding. I think there is a much simpler approach for this problem.

        var numberOfEnumValues = Enum.GetValues(typeof(Status)).Length;
        var users = fixture.CreateMany<User>(numberOfEnumValues);

In case the constructor is more complicated, with multiple Status values, or the model has property setters of Status type. Then you generally have a problem, and the generator might blow as well.

Say that:

    public class SuperUser : User
    {
        public SuperUser(Status status, Status shownStatus): base(status)
        {
        }
    }

Then this will never be evaluated:

    var users = fixture.Create<Generator<SuperUser>>();
    var offlineUser = users.Where(u => u.Status == Status.Offline).First();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!