1

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?

Fabio
  • 31,528
  • 4
  • 33
  • 72
Basin
  • 887
  • 1
  • 14
  • 28

1 Answers1

0

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

    }
}
CodexNZ
  • 724
  • 7
  • 15