MSTest是否支持泛型单元测试方法?其他C#测试框架呢?
我使用Visual Studio 2019、C#和MSTest单元测试框架(v2.2.10),在MSTest项目中定义了如下泛型测试方法:
[TestMethod] [DynamicData(nameof(TestData_Template), DynamicDataSourceType.Method)] public void String_DoesSomething_ExpectsSomeResult<T>(T input, string expected) { // Testing a template test method in MSTest (C#) // Arrange, act, assert string expectedLibrary = SomeLibrary.SomeFunction(input); Assert.AreEqual(expected, expectedLibrary); } // Generator method private static IEnumerable<object[]> TestData_Template() { // Generate some dynamic test data yield return new object[] { (int)7, "7" }; // Integer yield return new object[] { 0.123f, "0.123" }; // Float }
这段代码编译正常,但Test Explorer无法识别该测试方法。如果把方法特化为int或float类型(如下代码),Test Explorer就能正常识别并运行:
[TestMethod] [DynamicData(nameof(TestData_Int), DynamicDataSourceType.Method)] public void String_DoesSomething_ExpectsSomeResult_Int(int input, string expected) { // Arrange, act and assert string expectedLibrary = SomeLibrary.SomeFunction(input); Assert.AreEqual(expected, expectedLibrary); } private static IEnumerable<object[]> TestData_Int() { // Dynamic test data...but this time int only yield return new object[] { (int)7, "7" }; }
被测试的库方法SomeLibrary::SomeFunction定义正确且运行正常。我希望使用自包含的生成器方法,而非MSTest的DataRow属性来定义大量常量输入数据。
问题
- MSTest单元测试项目中能否使用泛型测试方法?
- NUnit或xUnit等其他C#单元测试框架是否支持该特性?
更新:有回答建议使用DataRow提供常量测试输入数据,但该方案对我无效,可能是针对不同版本的MSTest或Visual Studio。此外,即使DataRow支持泛型方法,除小量数据外的场景会显得繁琐,且注释维护性差。我需要的是将生成器方法与泛型单元测试方法配合使用的解决方案。
解答
1. MSTest的泛型测试方法支持情况
MSTest(v2.2.10版本)不支持未绑定的泛型测试方法。Test Explorer无法识别带泛型参数的[TestMethod],因为MSTest的测试发现机制要求测试方法必须是具体类型的,无法自动实例化未绑定的泛型方法。
若要在MSTest中复用跨类型的测试逻辑,可采用以下方案:
- 把通用测试逻辑提取到非测试的泛型辅助方法中,为每个目标类型编写具体的测试方法,在方法内调用辅助方法并绑定对应类型。
- 通过反射动态生成泛型方法实例,但这种方式复杂度高,不利于测试维护。
2. NUnit与xUnit的支持情况
NUnit
NUnit 完全支持泛型测试方法与动态数据生成器的结合。通过[TestCaseSource]属性指定数据生成器方法,NUnit会自动根据每个数据项的类型绑定泛型参数T,并生成独立的测试实例。
示例代码:
[TestFixture] public class GenericTests { [Test] [TestCaseSource(nameof(TestData_Template))] public void String_DoesSomething_ExpectsSomeResult<T>(T input, string expected) { string result = SomeLibrary.SomeFunction(input); Assert.AreEqual(expected, result); } private static IEnumerable<object[]> TestData_Template() { yield return new object[] { 7, "7" }; yield return new object[] { 0.123f, "0.123" }; } }
xUnit
xUnit 支持泛型测试方法,结合[Theory]和[MemberData]特性即可实现动态数据驱动的泛型测试。MemberData指向返回IEnumerable<object[]>的静态方法,xUnit会自动推断每个数据项对应的泛型参数类型。
示例代码:
public class GenericTests { [Theory] [MemberData(nameof(TestData_Template))] public void String_DoesSomething_ExpectsSomeResult<T>(T input, string expected) { string result = SomeLibrary.SomeFunction(input); Assert.Equal(expected, result); } public static IEnumerable<object[]> TestData_Template() { yield return new object[] { 7, "7" }; yield return new object[] { 0.123f, "0.123" }; } }
内容的提问来源于stack exchange,提问作者AlainD

