只要可以从参数中推断出泛型类型参数,NUnit 测试方法实际上可以是泛型的:
[TestCase(42)]
[TestCase("string")]
[TestCase(double.Epsilon)]
public void GenericTest<T>(T instance)
{
Console.WriteLine(instance);
}

如果无法推断出泛型参数,则测试运行程序将不知道如何解析类型参数:
[TestCase(42)]
[TestCase("string")]
[TestCase(double.Epsilon)]
public void GenericTest<T>(object instance)
{
Console.WriteLine(instance);
}

但在这种情况下,您可以实现自定义属性:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class TestCaseGenericAttribute : TestCaseAttribute, ITestBuilder
{
public TestCaseGenericAttribute(params object[] arguments)
: base(arguments)
{
}
public Type[] TypeArguments { get; set; }
IEnumerable<TestMethod> ITestBuilder.BuildFrom(IMethodInfo method, Test suite)
{
if (!method.IsGenericMethodDefinition)
return base.BuildFrom(method, suite);
if (TypeArguments == null || TypeArguments.Length != method.GetGenericArguments().Length)
{
var parms = new TestCaseParameters { RunState = RunState.NotRunnable };
parms.Properties.Set("_SKIPREASON", $"{nameof(TypeArguments)} should have {method.GetGenericArguments().Length} elements");
return new[] { new NUnitTestCaseBuilder().BuildTestMethod(method, suite, parms) };
}
var genMethod = method.MakeGenericMethod(TypeArguments);
return base.BuildFrom(genMethod, suite);
}
}
用法:
[TestCaseGeneric("Some response", TypeArguments = new[] { typeof(IMyInterface), typeof(MyConcreteClass) }]
public void MyMethod_GenericCall_MakesGenericCall<T1, T2>(string expectedResponse)
{
// whatever
}
以及类似的定制TestCaseSourceAttribute
:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class TestCaseSourceGenericAttribute : TestCaseSourceAttribute, ITestBuilder
{
public TestCaseSourceGenericAttribute(string sourceName)
: base(sourceName)
{
}
public Type[] TypeArguments { get; set; }
IEnumerable<TestMethod> ITestBuilder.BuildFrom(IMethodInfo method, Test suite)
{
if (!method.IsGenericMethodDefinition)
return base.BuildFrom(method, suite);
if (TypeArguments == null || TypeArguments.Length != method.GetGenericArguments().Length)
{
var parms = new TestCaseParameters { RunState = RunState.NotRunnable };
parms.Properties.Set("_SKIPREASON", $"{nameof(TypeArguments)} should have {method.GetGenericArguments().Length} elements");
return new[] { new NUnitTestCaseBuilder().BuildTestMethod(method, suite, parms) };
}
var genMethod = method.MakeGenericMethod(TypeArguments);
return base.BuildFrom(genMethod, suite);
}
}
用法:
[TestCaseSourceGeneric(nameof(mySource)), TypeArguments = new[] { typeof(IMyInterface), typeof(MyConcreteClass) }]