如何配置AutoFixture以在创建许多特定类型时使用枚举值作为种子
本文关键字:类型 枚举 种子 许多特 配置 何配置 AutoFixture 创建 | 更新日期: 2023-09-27 18:18:21
我有以下类型:
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
——应该用匿名数据填充。
问题:
如何配置自动夹具来做到这一点?
我试了下面这个:
注册更新
User
对象的集合:fixture.Register( () => Enum.GetValues(typeof(Status)).Cast<Status>().Select(s => new User(s)));
这种方法的问题是AutoFixture不填充其他属性,如
Name
自定义
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))));
那也没用。
你可以这样做:
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...
}
您可以声明并使用自定义,例如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];
}
}
根据Mark的回答,我现在使用的是:
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
我知道它已经得到了回答,Generator是一个非常有趣的发现。我认为有一个更简单的方法来解决这个问题。
var numberOfEnumValues = Enum.GetValues(typeof(Status)).Length;
var users = fixture.CreateMany<User>(numberOfEnumValues);
如果构造函数更复杂,有多个Status值,或者模型有Status类型的属性设置器。那么你通常会遇到问题,发电机也可能会爆炸。
说:
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();
AutoFixture 4.17.0的当前操作方式
fixture
.Build<User>()
.With(u => u.Status, Status.Offline)
.CreateMany(5)
.ToList();