我正在努力学习AutoFixture,我已经有了xUnit、NSubstitute和AutoFixture安装程序,可以用假货自动模拟属性(使用AutoFixture.AutoNSubstitute)。换句话说,如果我有以下接口
public interface IFoo
{
IBar1 Bar1 {get;}
IBar2 Bar2 {get; set;}
}尝试解析IFoo将自动解析和填充Bar1和Bar2。
对于具有接口、具体对象或结构类型属性的对象来说,一切都很好。但是,我在让AutoFixture自动创建抽象类型的属性时遇到了问题。
我尝试过使用TypeRelay作为抽象类型,所以
fixture.Customizations.Add(new TypeRelay(typeof (AbstractBase), typeof (ConcreteChild)));我试过用这种方式来说明
fixture.Customize<AbstractBase>(
composer =>
composer.FromFactory(
(string ChildParam1, string ChildParam2) => new ConcreteChild(ConcreteChildParam1, ConcreteChildParam2)));我试过使用各种定制的标本制作器。
通过属性类型解析:
var pi = request as PropertyInfo;
if (pi != null &&
pi.PropertyType == typeof(AbstractBase))
return context.Resolve(typeof(ConcreteChild));
return new NoSpecimen(request);通过类类型解析:
var pi = request as Type;
if (pi != null &&
pi == typeof (AbstractBase))
return context.Resolve(typeof(ConcreteChild));
return new NoSpecimen(request);在以上两种解决方案中,我还尝试了context.Create<ConcreteChild>()
最后,我尝试使用Register<AbstractBase>(fixture.Create<ConcreteChild>);语法。
它们似乎都无法自动填充对象上的属性。
令人恼火的是,我可以在一个单独的测试中显式地fixture.Create<AbstractBase>();,然后得到ConcreteChild,然后手工阻塞所有的东西,但是这种方式违背了AutoFixture的目的,不是吗?
有什么想法吗?
更新:
抽象类。我已经修剪了大部分不可靠的东西,当我假设它被调用时,我把ctor代码留在里面了?
public abstract class ChatEntityId
{
private string _localName;
protected ChatEntityId(string chatRoomName, string entityUid, ChatProtocol protocol)
{
ErrorChecker.NormalizeToNullIfNotSet(ref chatRoomName);
ErrorChecker.NormalizeToNullIfNotSet(ref entityUid);
if (chatRoomName == null && entityUid == null)
{
throw new ArgumentException("Both chatRoomName and entityUid may not be null at the same time.");
}
ChatRoomName = chatRoomName;
EntityUid = entityUid;
Protocol = protocol;
}
public string ChatRoomName { get; private set; }
public string EntityUid { get; private set; }
public bool Equals(ChatEntityId chatEntityId) { }
public override bool Equals(object obj) { }
public override int GetHashCode() {}
public string LocalName { get; }
public ChatProtocol Protocol { get; private set; }
public override string ToString() { }
}ChatProtocol是一个枚举,相当标准。
AutoPopulatedProperty ICustomization
public virtual void Customize(IFixture fixture)
{
fixture.Customize(new DomainCustomization());
// Replacement for the AutoNSubstituteCustomization, this Postprocessor will automatically create fake objects on properties.
fixture.ResidueCollectors.Add(
new Postprocessor(
new NSubstituteBuilder(
new MethodInvoker(
new NSubstituteMethodQuery())),
new AutoPropertiesCommand(
new PropertiesOnlySpecification())));
}
private class PropertiesOnlySpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
return request is PropertyInfo;
}
}发布于 2014-07-09 13:24:30
有些尴尬的是,我意识到NSubstitute有它所称的http://nsubstitute.github.io/help/auto-and-recursive-mocks/,这部分是我想要的,并解释了为什么我无法弄清楚一些自动模拟的属性是从哪里来的。问题是,它没有全面地做到这一点(很可能是正确的),而且据我所知,在这方面也不是真正可扩展的。
现在AutoFixture起作用了,在我们在Postprocessors NSubstituteBuilder中创建样本之后,调用AutoPropertiesCommand类并获取它确定的填充数据的适当属性。
不幸的是,这两个相关类(从泛型AutoPropertiesCommand类继承非泛型继承)中的任何一个逻辑都是不可重写的,这就是问题发生的地方。具体来说,AutoPropertiesCommand<T>有两个获取属性和字段的方法,然后它使用提供的IRequestSpecification (本例中的PropertiesOnlySpecification)过滤这些属性和字段。
有争议的方法
private IEnumerable<PropertyInfo> GetProperties(object specimen)
{
return from pi in this.GetSpecimenType(specimen).GetProperties(BindingFlags.Public | BindingFlags.Instance)
where pi.GetSetMethod() != null
&& pi.GetIndexParameters().Length == 0
&& this.specification.IsSatisfiedBy(pi)
select pi;
}因此,这里的解决方案要么提供我自己的AutoPropertiesCommand实现,而不受上述限制,要么为我遇到的每一种情况显式地创建自定义。我还没有决定我更喜欢哪种方法,但可能是前者。
作为一个边栏,似乎限制这两个方法作为保护虚拟,有什么特别的原因,除了“它只是这样编码的方式”?我相信,这些都是基本的AutoFixture类。
https://stackoverflow.com/questions/24435874
复制相似问题