我有以下问题。我想测试一个通用类MyClass <'T>。但是,我不太在意用于T的类型。 但是,当我在测试中创建MyClass的实例时,我需要指定T应该是什么。 我可以这样:
var sut = new MyClass<Object>();
它当然可以工作,但是,我不喜欢专门讲对象,因为它向阅读此测试的人暗示也许对象类型在这里具有某种意义。
我喜欢AutoFixture使用的方法,其中每个值都是使用fixture.Create<T>()
创建的,因为它向读者显示了该值并不是很重要。例子:
[Fact]
public void IntroductoryTest()
{
// Arrange
Fixture fixture = new Fixture();
int expectedNumber = fixture.Create<int>();
MyClass sut = fixture.Create<MyClass>();
// Act
int result = sut.Echo(expectedNumber);
// Assert
Assert.Equal(expectedNumber, result);
}
在上面的代码中,我们并不关心数字,因此我们将AutoFixture用作需要一些数字这一事实的抽象。
有没有类似的解决方案,但是关于泛型类使用的类型呢?
类似:var sut = MyClass<fixture.GenericType>();
我不在乎实际的类型是什么。进一步说明我的用例:我有用于注册MyClass的AutoFac模块。在我的测试中,我只想测试模块是否正确注册了MyClass。对于该注册,我不想指定要用于MyClass的确切类型。可以是任何一个。
答案 0 :(得分:1)
可能您可以定义一个基本类型,例如IBase
,其中所有T类型都实现IBase(Class1<T> where T : IBase
),然后您可以说var sut = new MyClass<IBase>();
答案 1 :(得分:1)
当前,AutoFixture不支持非封闭的通用类型激活,并且不太可能一天更改一次。
首先,这是由于C#语言本身仅出于反射目的而支持非封闭的泛型类型。在不关闭特定MyClass<>
的类型的情况下,您不能声明T
类型的变量。因此,即使使用AutoFixture替代类型并为您激活实例,也很难使用结果-您可能需要使用object
类型的变量,或者如果需要使用covariance类型支持这一点。这些选项似乎都不可用。
第二,任务本身非常困难,因为泛型可能会受到限制。有时约束可能会变得疯狂,例如具有循环依赖性:class MyClass<T1, T2> where T1 : T2 where T2 : IEnumerable<T1>
。 AutoFixture.Idioms
库已经尝试为GuardClauseAssertion
解决该问题,但是成功了is average。此功能需要动态类型生成(并非所有平台都支持BTW)和Reflection.Emit
API的非常高级的用法,这使得正确实现非常困难。