.net 如何配置AutoFixture在创建许多特定类型的对象时使用枚举值作为种子?

bogh5gae  于 2022-12-14  发布在  .NET
关注(0)|答案(5)|浏览(123)

我有以下类型:

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

现在,当执行fixture.CreateMany<User>时,我希望AutoFixture返回两个Users,每个状态一个。所有其他属性--比如Name--应该用匿名数据填充。

问题:

如何配置AutoFixture来完成此操作?
我尝试了以下方法:
1.注册User对象的消息集合:

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

这种方法的问题是AutoFixture不填充其他属性,如Name
1.自定义User以使用工厂并注册使用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))));

那也没用,种子没有被使用.

x8goxv8g

x8goxv8g1#

你可以这样做:

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...
}
qqrboqgw

qqrboqgw2#

您可以声明和使用自定义,例如StatusGenerator

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

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

StatusGenerator的一个 * 假设 * 实现如下:

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];
    }
}
xn1cxnb4

xn1cxnb43#

基于Mark's answer,这是我现在使用的:

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
ktca8awb

ktca8awb4#

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

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

w1jd8yoj5#

当前使用AutoFixture 4.17.0执行此操作的方法

fixture
.Build<User>
.With(u => u.Status, Status.Offline)
.CreateMany(5)
.ToList();

相关问题