2015-11-25 4 views
3

Итак, у меня есть объект с большим количеством свойств IEnumerable. В модульном тесте я хочу сделать что-то вроде этого:Настройка AutoFixture при создании одного объекта

var subsequentAgreement = _fixture.Build<Foo>() 
              .With(dto => dto.Bars, 
               _fixture.CreateMany<Bar>()) 
              .Create(); 

И для других IEnumerable<T> свойств я хочу Enumerable.Empty<T>()

У меня есть ISpecimenBuilder

public class EmptyEnumerableBuilder : ISpecimenBuilder 
{ 
    public object Create(object request, ISpecimenContext context) 
    { 
     object returnObject = new NoSpecimen(request); 
     var type = request as Type; 
     if (type != null && type.IsGenericType) 
     { 
      var typeArguments = type.GetGenericArguments(); 
      if(!typeArguments.Any() || typeof(IEnumerable<>) == type.GetGenericTypeDefinition()) 
       returnObject = Array.CreateInstance(typeArguments.Single(), 0); 
     } 

     return returnObject; 
    } 
} 

, который я добавить, как так : _fixture.Customizations.Add(new EmptyEnumerableBuilder()); И это работает просто отлично, за исключением всех других объектов, которые я создаю, теперь есть пустые перечисления.

Я ищу способ применения этого EmptyEnumerableBuilder для одного _fixture.Build<>() и оставить все остальное по умолчанию, но я не могу найти способ.

Я попытался с помощью ограничения типа как так:

_fixture.Customize<SubsequentAgreementLimitationsDto>(composer => new EmptyEnumerableBuilder()); 

Но странно все другие объекты, созданные арматуре еще пустые перечислимых

+0

Что случилось с первым блоком кода? –

+0

Ничего, это то, как я хочу, но нормальное поведение автопотока приведет к созданию стандартного списка из 3-х элементов в IEnumerable . и я хотел бы изменить это значение по умолчанию на Enumerable.Empty (). для этого _fixture.Build или при создании объекта типа Foo. – LordSauron

+0

А, я вижу. [Рассмотрите возможность создания свойств вашей коллекции только для чтения] (https://msdn.microsoft.com/en-us/library/dn169389.aspx), тогда этого не произойдет. –

ответ

1

Если вам нужно что-то условность приводом, вы можете быть в состоянии используйте Albedo, чтобы удалить все доступные для записи свойства IEnumerable<>. Вы могли бы начать с чем-то вроде этого:

public class EmtpyEnumerables : ReflectionVisitor<object> 
{ 
    private object value; 

    public EmtpyEnumerables(object value) 
    { 
     this.value = value; 
    } 

    public override object Value 
    { 
     get { return value; } 
    } 

    public override IReflectionVisitor<object> Visit(PropertyInfoElement propertyInfoElement) 
    { 
     var pi = propertyInfoElement.PropertyInfo; 
     if (pi.PropertyType.IsConstructedGenericType && 
      pi.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>) && 
      pi.CanWrite) 
     { 
      var elementType = pi.PropertyType.GetGenericArguments().Single(); 
      pi.SetValue(value, Array.CreateInstance(elementType, 0)); 
      return this; 
     } 

     return base.Visit(propertyInfoElement); 
    } 
} 

Если предположить, что Foo выглядит следующим образом:

public class Foo 
{ 
    public IEnumerable<Bar> Bars { get; set; } 

    public IEnumerable<Baz> Bazs { get; set; } 

    public IEnumerable<Qux> Quxs { get; set; } 

    public string Corge { get; set; } 

    public int Grault { get; set; } 
} 

Тогда следующий тест пройден:

[Fact] 
public void FillBarsZeroOutAllOtherSequences() 
{ 
    var fixture = new Fixture(); 

    var actual = fixture.Create<Foo>(); 
    new TypeElement(actual.GetType()).Accept(new EmtpyEnumerables(actual)); 
    actual.Bars = fixture.CreateMany<Bar>(); 

    Assert.NotEmpty(actual.Bars); 
    Assert.Empty(actual.Bazs); 
    Assert.Empty(actual.Quxs); 
    Assert.NotEqual(default(string), actual.Corge); 
    Assert.NotEqual(default(int), actual.Grault); 
} 

Если вы думаете, что это слишком много потрудились напишите new TypeElement(actual.GetType()).Accept(new EmtpyEnumerables(actual));, я уверен, что вы можете понять, чтобы скрыть его в вспомогательном методе.

+0

Wow спасибо за ответ, так как один из вас много преданных последователей. Я бы хотел отметить это как ответ, но, хотя это сработает, потребуются другие зависимости, поэтому на самом деле он не отвечает на этот вопрос. Так что не знаю, как вести себя в этом случае: - $ – LordSauron

+0

@LordSauron Если это не отвечает на ваш вопрос, тогда вам не обязательно указывать его как ответ. Это прекрасно.Это просто лучшее, что я мог придумать ... –

Смежные вопросы