所以,我有一个具有大量IEnumerable属性的对象。 在单元测试中,我想做这样的事情:
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());
但奇怪的是,由fixture创建的所有其他对象仍然具有空的枚举
答案 0 :(得分: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));
太麻烦了,我相信你可以想出用辅助方法隐藏它。