需要泛型类型时进行单元测试
Unit testing when generic type is needed
我有以下问题。我想测试通用 class MyClass<'T>。但是,我并不真正关心用于 T 的类型。
但是,当我在测试中创建 MyClass 的实例时,我需要指定 T 应该是什么。
我可以这样做:
var sut = new MyClass<Object>();
它当然有效,但是,我不喜欢专门放置对象,因为它向阅读此测试的人暗示对象类型在这里可能有些重要。
我喜欢 AutoFixture 使用的方法,其中每个值都是使用 fixture.Create<T>()
创建的,因为它向 reader 表明该值并不是很重要。例子:
[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 作为对需要一些数字这一事实的抽象。
是否有类似的解决方案,但关于与通用 classes 一起使用的类型?
类似于:var sut = MyClass<fixture.GenericType>();
我在这里不关心实际类型是什么。进一步解释我的用例:我有用于注册 MyClass 的 AutoFac 模块。在我的测试中,我只想测试模块是否正确注册了 MyClass。对于该注册,我不想指定要用于 MyClass 的某些确切类型。可以是任何一个。
也许你可以定义一个基类型,比如 IBase
,其中你所有的 T 类型都实现了 IBase (Class1<T> where T : IBase
),然后你可以说 var sut = new MyClass<IBase>();
目前 AutoFixture 不支持非封闭泛型激活,不太可能有一天会改变。
首先是因为C#语言本身支持非封闭泛型,仅用于反射目的。您不能在不关闭特定 T
类型的情况下声明 MyClass<>
类型的变量。因此,即使 AutoFixture 替换类型并为您激活一个实例,也很难处理结果 - 如果您需要,您要么需要使用 object
类型的变量,要么依赖 covariance类型支持这一点。 None 这些选项看起来可用。
其次,任务本身非常艰巨,因为泛型类型可能有限制。有时约束会变得疯狂,例如具有循环依赖性:class MyClass<T1, T2> where T1 : T2 where T2 : IEnumerable<T1>
。 AutoFixture.Idioms
库已经尝试为 GuardClauseAssertion
解决该问题,但成功了 is average。此功能需要动态类型生成(顺便说一句,并非所有平台都支持)和 Reflection.Emit
API 的非常高级的用法,这使得它很难正确实现。
我有以下问题。我想测试通用 class MyClass<'T>。但是,我并不真正关心用于 T 的类型。 但是,当我在测试中创建 MyClass 的实例时,我需要指定 T 应该是什么。 我可以这样做:
var sut = new MyClass<Object>();
它当然有效,但是,我不喜欢专门放置对象,因为它向阅读此测试的人暗示对象类型在这里可能有些重要。
我喜欢 AutoFixture 使用的方法,其中每个值都是使用 fixture.Create<T>()
创建的,因为它向 reader 表明该值并不是很重要。例子:
[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 作为对需要一些数字这一事实的抽象。
是否有类似的解决方案,但关于与通用 classes 一起使用的类型?
类似于:var sut = MyClass<fixture.GenericType>();
我在这里不关心实际类型是什么。进一步解释我的用例:我有用于注册 MyClass 的 AutoFac 模块。在我的测试中,我只想测试模块是否正确注册了 MyClass。对于该注册,我不想指定要用于 MyClass 的某些确切类型。可以是任何一个。
也许你可以定义一个基类型,比如 IBase
,其中你所有的 T 类型都实现了 IBase (Class1<T> where T : IBase
),然后你可以说 var sut = new MyClass<IBase>();
目前 AutoFixture 不支持非封闭泛型激活,不太可能有一天会改变。
首先是因为C#语言本身支持非封闭泛型,仅用于反射目的。您不能在不关闭特定 T
类型的情况下声明 MyClass<>
类型的变量。因此,即使 AutoFixture 替换类型并为您激活一个实例,也很难处理结果 - 如果您需要,您要么需要使用 object
类型的变量,要么依赖 covariance类型支持这一点。 None 这些选项看起来可用。
其次,任务本身非常艰巨,因为泛型类型可能有限制。有时约束会变得疯狂,例如具有循环依赖性:class MyClass<T1, T2> where T1 : T2 where T2 : IEnumerable<T1>
。 AutoFixture.Idioms
库已经尝试为 GuardClauseAssertion
解决该问题,但成功了 is average。此功能需要动态类型生成(顺便说一句,并非所有平台都支持)和 Reflection.Emit
API 的非常高级的用法,这使得它很难正确实现。