首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AutoMocking属性在抽象属性上失败?

AutoMocking属性在抽象属性上失败?
EN

Stack Overflow用户
提问于 2014-06-26 16:36:58
回答 1查看 672关注 0票数 1

我正在努力学习AutoFixture,我已经有了xUnit、NSubstitute和AutoFixture安装程序,可以用假货自动模拟属性(使用AutoFixture.AutoNSubstitute)。换句话说,如果我有以下接口

代码语言:javascript
复制
public interface IFoo
{
    IBar1 Bar1 {get;}
    IBar2 Bar2 {get; set;}
}

尝试解析IFoo将自动解析和填充Bar1和Bar2。

对于具有接口、具体对象或结构类型属性的对象来说,一切都很好。但是,我在让AutoFixture自动创建抽象类型的属性时遇到了问题。

我尝试过使用TypeRelay作为抽象类型,所以

代码语言:javascript
复制
fixture.Customizations.Add(new TypeRelay(typeof (AbstractBase), typeof (ConcreteChild)));

我试过用这种方式来说明

代码语言:javascript
复制
fixture.Customize<AbstractBase>(
            composer =>
                composer.FromFactory(
                    (string ChildParam1, string ChildParam2) => new ConcreteChild(ConcreteChildParam1, ConcreteChildParam2)));

我试过使用各种定制的标本制作器。

通过属性类型解析:

代码语言:javascript
复制
var pi = request as PropertyInfo;

if (pi != null &&
    pi.PropertyType == typeof(AbstractBase))
    return context.Resolve(typeof(ConcreteChild));

return new NoSpecimen(request);

通过类类型解析:

代码语言:javascript
复制
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代码留在里面了?

代码语言:javascript
复制
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

代码语言:javascript
复制
    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;
        }
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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)过滤这些属性和字段。

有争议的方法

代码语言:javascript
复制
    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类。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24435874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档