[英]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
。 有没有办法同时注入IInterface
和Class
以便为两者返回相同的实例?
请注意,我想使用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会更容易:
[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
映射IInterface
到Class
,这意味着所有请求IInterface
将被转发到了请求Class
。 当Class
被冻结时,这意味着不仅Class
被冻结,而且IInterface
被IInterface
。
当然,您可以在具体的类参数上应用[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.