Mik*_*EEE 5 c# unit-testing 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.
}
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题IInterface是注入,而Class不是.有没有办法注入两者IInterface,Class以便为两者返回相同的实例?
请注意,我想使用ICustomization(或在一个内ICustomization)而不是测试方法的属性.我希望在这两个类上进行自定义注入.如果我[Frozen( Matching.ImplementedInterfaces)]Class item用作参数,则它不起作用,因为冻结的类会覆盖方法中的注入值ICustomization.Customize.
另请注意,这是示例代码,而不是我如何使用它.在xUnit测试方法中,我希望Class指定为参数的实例在IInstance上面被冻结:
public void MyTest( IInterface @interface, Class implementation )
{
Assert.Same( @interface, implementation );
}
Run Code Online (Sandbox Code Playgroud)
当然,您可以将[Frozen]属性应用于具体类参数并指定ImplementedInterfaces为匹配条件:
[Theory, AutoData]
public void Test(
[Frozen(Matching.ImplementedInterfaces)]Class implementation,
IInterface @interface)
{
Assert.Same(implementation, @interface);
}
Run Code Online (Sandbox Code Playgroud)
这告诉 AutoFixture每次必须为其实现的任何接口创建值时提供相同的 实例。Class
如果你仔细观察这个Inject方法,你会发现它实际上是一个泛型方法,但是当你使用它时就会推断出类型参数.如果你想要冻结两者,你可以 - 你只需要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);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,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);
}
Run Code Online (Sandbox Code Playgroud)
总而言之,我认为简单地使用内置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);
}
Run Code Online (Sandbox Code Playgroud)
TypeRelay映射IInterface到Class,这意味着所有请求IInterface都将被转发给请求Class.当Class冻结时,这意味着不仅Class冻结,而且冻结IInterface.
好吧,这花了很长时间才弄清楚,但这个问题/场景最终是由于我的设计不佳以及对 AutoFixture 缺乏经验和学习造成的。我试图做的实际场景是向我的固定装置注册一个 IoC 容器,并且我希望 IServiceLocator 及其实现都向固定装置注册,以便它们可用于将值注入到当前的测试方法中。
通过添加用于将请求中继到提供的 IServiceLocator 的自定义(在本问题中也提到过)解决了这个问题。
此外,我确实制作了一个使用Dynamitey的扩展方法来完成我正在寻找的功能,但它不再使用,我可能会在某个时候删除。
所以答案是:如果你出于某种原因想要这样做,那么你很可能做错了。我很想删除这个答案,但我会将其留在这里,以防像我这样的另一个新手遇到同样的问题并可能从中受益。
最后,我要感谢@enrico-campidoglio 和@mark-seemann 的耐心和真正信息丰富/高质量的答案/帮助(也感谢没有人对这个问题投反对票)。我知道这里的标准很高@Stack Overflow,在发布这个问题之前我可能应该多一点耐心。
| 归档时间: |
|
| 查看次数: |
1305 次 |
| 最近记录: |