繁体   English   中英

在AutoFixture中注入接口和实现

[英]Inject Both Interface and Implementation in AutoFixture

考虑以下类别:

public interface IInterface {}
public class Class : IInterface {}

public class Customization : ICustomization
{
    readonly IInterface item;

    public Customization() : this( new Class() ) {}

    public Customization( IInterface item )
    {
        this.item = item;
    }

    public void Customize( IFixture fixture )
    {
        fixture.Inject( item );
        var created = fixture.Create<Class>(); // Would like this to resolve as item from previous line.
    }
}

IInterface是注入了IInterface ,而没有注入Class 有没有办法同时注入IInterfaceClass以便为两者返回相同的实例?

请注意,我想使用ICustomization (或在ICustomization )执行此操作,而不要使用测试方法上的属性。 我希望对这两个类进行定制注入。 如果我使用[Frozen( Matching.ImplementedInterfaces)]Class item作为参数,则该[Frozen( Matching.ImplementedInterfaces)]Class item将不起作用,因为被冻结的Class会覆盖ICustomization.Customize方法中的注入值。

另外请注意,这是示例代码,而不是我的用法。 在xUnit测试方法中,我希望将指定为参数的Class实例作为上述冻结的IInstance

public void MyTest( IInterface @interface, Class implementation )
{
    Assert.Same( @interface, implementation );
}

如果您绝对必须自己做

如果仔细看一下Inject方法,您会注意到它实际上是一个通用方法,但是当您像使用它一样使用它时,会推断出type参数。 如果您想同时冻结两者,则可以-您只需为每种类型调用Inject

这是经过稍微修改的Customization 为了防止可能的无效转换,我对其进行了更改,以使其item字段(以及相应的item构造函数参数)的类型为Class

public class Customization : ICustomization
{
    readonly Class item;

    public Customization() : this(new Class()) { }

    public Customization(Class item)
    {
        this.item = item;
    }

    public void Customize(IFixture fixture)
    {
        fixture.Inject(item);
        fixture.Inject<IInterface>(item);
    }
}

请注意, Customize两次注入相同的项目。 在第一行中,编译器将泛型类型参数推断为Class ,而在第二行中,显式定义了类型参数IInterface

使用此实现,以下测试将通过:

[Fact]
public void UseCustomization()
{
    var fixture = new Fixture().Customize(new Customization());

    var c = fixture.Create<Class>();
    var i = fixture.Create<IInterface>();

    Assert.Equal(c, i);
}

使用内置的API

综上所述,我认为简单地使用内置API会更容易:

[Fact]
public void UseTypeRelay()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(
        new TypeRelay(
            typeof(IInterface),
            typeof(Class)));
    fixture.Freeze<Class>();

    var c = fixture.Create<Class>();
    var i = fixture.Create<IInterface>();

    Assert.Equal(c, i);
}

TypeRelay映射IInterfaceClass ,这意味着所有请求IInterface将被转发到了请求Class Class被冻结时,这意味着不仅Class被冻结,而且IInterfaceIInterface

当然,您可以在具体的类参数上应用[Frozen]属性,并指定ImplementedInterfaces作为匹配条件:

[Theory, AutoData]
public void Test(
    [Frozen(Matching.ImplementedInterfaces)]Class implementation,
    IInterface @interface)
{
    Assert.Same(implementation, @interface);
}

这告诉AutoFixture每次必须为其任何实现的接口创建值时都提供相同的 Class实例。

好的,这花了很长时间才弄清楚,但是这个问题/场景最终是由于我的设计不良以及对AutoFixture的缺乏了解和学习。 我尝试做的实际场景是在我的灯具中注册一个IoC容器,我希望IServiceLocator及其实现都在灯具中注册,以便它们可用于将值注入当前的测试方法中。

通过添加用于将请求中继到提供的IServiceLocator 的Customization解决了此问题在此问题中也提到 )。

另外,我确实做了一个扩展程序该扩展方法使用了Dynamitey来实现我一直在寻找的东西,但是不再使用,因此我可能会在某个时候删除它。

因此,答案是: 如果出于某种原因要执行此操作,则很可能出错 我很想删除这个答案,但是我会把它留在这里,以防其他像我这样的新手遇到相同的问题并可能从中受益。

最后,我要感谢@ enrico-campidoglio和@ mark-seemann的耐心和真正有益的/高质量的答案/帮助(也没有人赞成这个问题)。 我知道这里的标准设置很高@ Stack Overflow,在发布此问题之前,我可能应该多耐心一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM