How to configure AutoFixture to use the enum value as a seed when creating many specific types?

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 that you are doing fixture.CreateMany<User> , I want AutoFixture to return two Users , one for each state. All other properties, such as Name , must be populated with anonymous data.

Question:
How to configure AutoFixture for this?


I tried the following:

  • Register the news collection in User :

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

    The problem with this approach is that AutoFixture does not populate other properties like Name

  • Configure User to use 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. Seed is not used.

+6
c # autofixture
source share
4 answers

You can do it:

 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 use 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... } 
+5
source share

You can declare and use a setting, for example. StatusGenerator :

 var fixture = new Fixture(); fixture.RepeatCount = 2; fixture.Customizations.Add(new StatusGenerator()); var result = fixture.CreateMany<User>(); 

The hypothetical implementation of StatusGenerator may be as follows:

 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]; } } 
+3
source share

Based on the Mark the 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 
+2
source share

I know that this has already been 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 complex, with several status values ​​or the model has property identifiers of type Status. Then, as a rule, you have a problem, and the generator can hit too.

Say that:

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

Then it will never be appreciated:

  var users = fixture.Create<Generator<SuperUser>>(); var offlineUser = users.Where(u => u.Status == Status.Offline).First(); 
+2
source share

All Articles