Как обновить настройки Fixture в AutoFixture - PullRequest
0 голосов
/ 18 сентября 2018

В классе Testbase он настраивает MyClass вот так

fixture.Customize<MyClass>(c => c.Without(r => r.Foo));

и в подклассе Testbase он имеет

fixture.Customize<MyClass>(c => c.Without(r => r.Bar));

Проблема в том, что я хочу добавить больше настроек в MyClass, но кажется, что последние выигрывают / переопределяют первые, поэтому он все еще устанавливает MyClass.Foo. Так как же я могу обновить настройку вместо ее переопределения?

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Возможно, но, насколько я знаю, вам придется написать свой собственный прибор для перехода в метод Customize ICustomization.

Вот пример, который я сделал: https://github.com/LethargicDeveloper/Lift.AutoFixture

Я создал метод расширения под названием «Compose ()» принимает ICustomization.Он внедряет специальный прибор в классы настройки, которые вы определили, и объединяет все настройки перед добавлением их в коллекцию настроек вашего исходного прибора.

Ниже приведен фрагмент кода, который выполняет большую часть работы.Fixture имеет коллекцию настроек, которая содержит все настройки, которые будут применены.Коллекция Customization - это List , и, насколько я знаю, нет простого способа узнать, какие типы будет создавать каждый сборщик.Поэтому в моем новом приборе я держу информацию о типе в Словаре и жду, пока вы не вызовете BuildFixture, прежде чем фактические настройки будут добавлены в список настроек.

Ключ находится в методе Customize .Это метод в приборе, который вы вызываете для создания своей настройки, поэтому мы переопределяем его.Каждый раз, когда она вызывается, текущая настройка извлекается из списка «Строители» для данного типа и составляется с новой настройкой, а затем возвращается в список «Строители».

internal class ComposableCustomizationBuilder : IFixture
{
    private readonly IFixture fixture;

    public ComposableCustomizationBuilder(IFixture fixture)
    {
        this.fixture = fixture;
        this.Builders = new Dictionary<Type, object>();
    }

    // most of the IFixture methods have been removed for brevity since they just return the this.fixture implementation.

    internal Dictionary<Type, object> Builders { get; }

    public IFixture Customize(ICustomization customization)
    {
        customization.Customize(this);
        return this;
    }

    public void Customize<T>(Func<ICustomizationComposer<T>, ISpecimenBuilder> composerTransformation)
    {
        if (!this.Builders.TryGetValue(typeof(T), out object builder))
        {
            var specimenBuilder = composerTransformation(SpecimenBuilderNodeFactory.CreateComposer<T>().WithAutoProperties(true));
            this.Builders.Add(typeof(T), new NodeComposer<T>(specimenBuilder));
            return;
        }

        this.Builders[typeof(T)] = composerTransformation(builder as ICustomizationComposer<T>);
    }

    internal IFixture BuildFixture()
    {
        if (this.fixture is ComposableCustomizationBuilder)
        {
            return this;
        }

        foreach (var builder in this.Builders)
        {
            var specimenBuilder = builder.Value as ISpecimenBuilder;
            this.fixture.Customizations.Add(specimenBuilder);
        }

        return this.fixture;
    }
}

Используя ваш пример, вы можете написать его так:это:

var fixture = new Fixture()
  .Compose<NoBar>()
  .Compose<NoFoo>()
  .Compose();

var result = fixture.Create<MyClass>();

// All the properties should be set as normal by autofixture except for both Foo and Bar which should be omitted.

public class NoBar : ICustomization
{
   public void Customize(IFixture fixture)
   {
      fixture.Customize<MyClass>(c => c.Without(r => r.Bar));
   }
}

public class NoFoo : ICustomization
{
   public void Customize(IFixture fixture)
   {
      fixture.Customize<MyClass>(c => c.Without(r => r.Foo));
   }
}
0 голосов
/ 30 сентября 2018

Короткий ответ: вы не можете этого сделать. Customize<> API всегда добавляет новую настройку, поэтому предыдущая переопределяется - это сделано специально.

В качестве возможного обходного пути вы можете использовать несколько иной синтаксис для пропуска отдельных свойств:

fixture.Customizations.Add(
    new Omitter(
        new EqualRequestSpecification(
            typeof(MyClass).GetProperty(nameof(MyClass.Foo)))));

Таким образом, вы можете добавлять настройки и расширять список исключений позже:

fixture.Customizations.Add(
    new Omitter(
        new EqualRequestSpecification(
            typeof(MyClass).GetProperty(nameof(MyClass.Bar)))));

Имейте в виду, что этот подход влияет на всю иерархию классов, если у вас есть наследование. Поэтому, если вы пропустите BaseClass.Foo, оно также пропустит свойство Foo в каждом дочернем классе.

...