请考虑以下代码:
public class TestingSample
{
public class FactoryClass : Class {}
public class Class : IInterface {}
public interface IInterface {}
public class AutoData : AutoDataAttribute
{
public AutoData() : base( Create() ) {}
static IFixture Create()
{
var fixture = new Fixture();
fixture.Customize<IInterface>( composer => composer.FromFactory( () => new FactoryClass() ) );
fixture.Customize<Class>( composer => composer.FromFactory( () => new FactoryClass() ) );
return fixture;
}
}
[Theory, TestingSample.AutoData]
public void OldSkool( [Frozen( As = typeof(IInterface) )]Class first, Class second, IInterface third )
{
Assert.IsType<FactoryClass>( first );
Assert.Same( first, second );
Assert.Same( first, third );
}
[Theory, TestingSample.AutoData]
public void DirectBaseType( [Frozen( Matching.ExactType )]Class first, Class second )
{
Assert.IsType<FactoryClass>( first );
Assert.Same( first, second );
}
[Theory, TestingSample.AutoData]
public void ImplementedInterfaces( [Frozen( Matching.ImplementedInterfaces )]Class first, IInterface second )
{
Assert.IsType<FactoryClass>( first );
Assert.Same( first, second ); // The Fails.
}
}正如您(希望)所看到的,ImplementedInterfaces测试失败了。由于FrozenAttribute.As已被废弃,并且用户被指示移动到Match枚举,我的期望是它的行为将与以前一样。
但是,Match.ImplementedInterfaces的行为似乎与Match.ExactType和FrozenAttribute.As都不一样。
我确实做了一些探索,并看到Match.ExactType和FrozenAttribute.As使用SeedRequestSpecification,而Match.ImplementedInterfaces只匹配Type请求。
是否有可能在这种行为上建立一些背景?这是故意的吗?如果是这样的话,是否有已知的设计建议来使用Match.ImplementedInterfaces恢复旧的行为?
发布于 2016-01-23 17:45:07
首先,附带条件:在我的机器上,使用AutoFixture 3.39.0,OP中提供的代码的行为不像描述的那样。不同的是,这个测试中的第一个断言通过了:
[Theory, TestingSample.AutoData]
public void ImplementedInterfaces(
[Frozen(Matching.ImplementedInterfaces)]Class first,
IInterface second)
{
Assert.IsType<FactoryClass>(first); // passes
Assert.Same(first, second); // fails
}不过,我承认第二个断言失败(有点)令人吃惊。
简短的解释是,对于当前的实现,冻结是在反射时完成的,而不是在运行时完成的。当AutoFixture.Xunit2确定要冻结什么时,它会查看应用[Frozen]属性的参数的类型。这是Class,而不是FactoryClass,所以结果是FactoryClass根本没有冻结!
您可以从这个测试中看出这一点:
[Theory, TestingSample.AutoData]
public void FactoryClassIsNotFrozen(
[Frozen(Matching.ImplementedInterfaces)]Class first,
FactoryClass second)
{
Assert.IsType<FactoryClass>(first); // passes
Assert.IsType<FactoryClass>(second); // passes
Assert.Same(first, second); // fails
}这是最好的实现吗?也许不是,但这是目前的工作方式。有AutoFixture GitHub存储库中的一个未决问题建议应该重构冻结实现,使其更像DI容器的Singleton生存期。这可能会改变这种特殊情况下的行为,使之更适合这种情况。它是否也会有一些缺点,我现在还不能判断。
当我们重新设计[Frozen]属性以使用更灵活的Matching规则时,我意识到新系统无法100%地替代旧的As属性。我还是觉得这样的交易是值得的。
虽然As使您能够让这个特定特性工作,但这是因为作为程序员,您知道Class实现了IInterface,因此[Frozen(As = typeof(IInterface))]注释是有意义的。
你可以说As更灵活,但这主要是因为它没有内置的智能。你也可以编写[Frozen(As = typeof(IAsyncResult))],它编译得很好,但在运行时失败了,因为这完全是胡说八道。
是否有已知的使用Match.ImplementedInterfaces来恢复旧行为的设计建议?
是的,考虑简化测试系统(SUT)的设计。
AutoFixture最初被认为是一个测试驱动的开发工具,而这仍然是它的主要目的。本着古斯的精神,我们应该听的测试。如果测试很难写,第一个反应应该是简化SUT。AutoFixture倾向于从测试中放大这种反馈。
您真的需要匹配既实现接口又从基类派生的东西吗?为什么?
能让它更简单吗?
https://stackoverflow.com/questions/34840015
复制相似问题