简体   繁体   中英

How to generate instance with fixed value for certain property?

We use AutoFixture for test data generation, one of the scenarios requires us to provide fixed data, so we can test the method below.

public enum OrderState { Initial = 0, State1 = 1, State2 = 2, State3 = 3 };

public record Order(Guid Id, string Reference, OrderState State);   

public static class Filter
{
  public static IEnumerable<Order> ByState(IEnumerable<Order> orders, OrderState state)
  {
    return orders.Where(order => order.State == state);
  }
}

Test

[Fact]
public void Returns_only_orders_with_initial_state()
{
  // Arrange
  var fixture = new Fixture();
  var order1 = fixture.Build(o => o.State, OrderState.Initial).Create();
  var allOrders = new[] 
  {
    fixture.Build(o => o.State, OrderState.State1).Create(),
    fixture.Build(o => o.State, OrderState.State2).Create(),
    fixture.Build(o => o.State, OrderState.State3).Create(),
    order1
  };
   
  // Act
  var actual = new Filter().ByState(allOrders, OrderState.Initial);

  // Assert
  actual.Should().BeEquivalentTo(new[] { order1 });
}

Test fails because AutoFixture can not write to readonly properties - I understand that.

How can I create an instance with fixed value for the State property, but still use "random" values for other properties?

You can achieve this using AutoFixture's SpecimenBuilder facility.

An example of his can be found in this post

A demonstration for your use case:

using AutoFixture.Kernel;
using System.Reflection;


namespace Example
{
    public enum OrderState { Initial = 0, State1 = 1, State2 = 2, State3 = 3 };

    public record Order(Guid Id, string Reference, OrderState State);

    public class OrderStateArg : ISpecimenBuilder
    {
        private readonly OrderState _state;

        public OrderStateArg(OrderState state)
        {
            _state = state;
        }

        public object Create(object request, ISpecimenContext context)
        {
            var pi = request as ParameterInfo;
        
            if (pi == null)
            {
                return new NoSpecimen();
            }

            if (pi.Member.DeclaringType != typeof(Order) ||
                pi.ParameterType != typeof(OrderState) ||
                pi.Name != "State")
            {
                return new NoSpecimen();
            }

            return _state;
        }
    }

    public static class Filter
    {
        public static IEnumerable<Order> ByState(IEnumerable<Order> orders, OrderState state)
        {
            return orders.Where(order => order.State == state);
        }
    }

    public class Class1
    {
        [Fact]
        public void Returns_only_orders_with_initial_state()
        {
            var fixture = new Fixture();
            fixture.Customizations.Add(new OrderStateArg(OrderState.Initial));

            var order1 = fixture.Create<Order>();

            fixture.Customizations.Clear();

            var allOrders = new Order[] 
            {
                fixture.Create<Order>(),
                fixture.Create<Order>(),
                fixture.Create<Order>(),
                order1
            };

            // Act
            // Note on your original code, Filter is a static class
            // so calling its methods do not require the new keyword.
            var actual = Filter.ByState(allOrders, OrderState.Initial);

            // Assert
            actual.Should().BeEquivalentTo(new[] { order1 });
        }

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM