需要泛型时的单元测试

时间:2019-02-07 12:47:35

标签: c# unit-testing generics autofixture

我有以下问题。我想测试一个通用类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的确切类型。可以是任何一个。

2 个答案:

答案 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的非常高级的用法,这使得正确实现非常困难。