8

I have the following types:

public enum Status
{
    Online,
    Offline
}

public class User
{
    private readonly Status _status;
    public User(Status status) { _status = status; }
    public Status Status {get {return _status; }}
    public string Name {get;set;}
}

Now, when executing fixture.CreateMany<User> I want AutoFixture to return two Users, one per status. All other properties - like Name - should be filled with anonymous data.

Question:
How to configure AutoFixture to do this?


I tried the following this:

  1. Register collection that news up the User object:

    fixture.Register(
        () => Enum.GetValues(typeof(Status)).Cast<Status>().Select(s => 
            new User(s)));
    

    The problem with this approach is that AutoFixture doesn't fill the other properties like Name

  2. Customize User to use a factory and register a collection that uses fixture.Create:

        f.Customize<User>(c => c.FromFactory((Status s) => new User(s)));
        f.Register(() =>
            Enum.GetValues(typeof(Status))
                .Cast<Status>()
                .Select(s => (User)f.Create(new SeededRequest(typeof(User), s),
                                            new SpecimenContext(f))));
    

    That didn't work either. The seed isn't being used.

4

4 回答 4

5

你可以这样做:

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

如果您使用的是 AutoFixture.Xunit,则声明式等效项是:

[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...
}
于 2013-06-18T13:23:10.543 回答
5

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];
    }
}
于 2013-06-14T20:52:30.663 回答
4

根据马克的回答,这就是我现在使用的:

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
于 2013-06-25T15:43:10.513 回答
2

我知道它已经被回答了,而生成器是一个非常有趣的发现。我认为这个问题有一个更简单的方法。

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

如果构造函数更复杂,具有多个状态值,或者模型具有状态类型的属性设置器。然后你通常会遇到问题,发电机也可能会爆炸。

比如说:

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

那么这将永远不会被评估:

    var users = fixture.Create<Generator<SuperUser>>();
    var offlineUser = users.Where(u => u.Status == Status.Offline).First();
于 2013-07-30T21:39:45.690 回答