NUnit TestCase with Generics

后端 未结 9 855
梦毁少年i
梦毁少年i 2021-01-31 13:53

Is there any way to pass generic types using a TestCase to a test in NUnit?

This is what I would like to do but the syntax is not correct...

<         


        
9条回答
  •  感情败类
    2021-01-31 14:30

    NUnit test methods actually can be generic as long as the generic type arguments can be inferred from parameters:

    [TestCase(42)]
    [TestCase("string")]
    [TestCase(double.Epsilon)]
    public void GenericTest(T instance)
    {
        Console.WriteLine(instance);
    }
    

    If the generic arguments cannot be inferred, the test runner will not have a clue how to resolve type arguments:

    [TestCase(42)]
    [TestCase("string")]
    [TestCase(double.Epsilon)]
    public void GenericTest(object instance)
    {
        Console.WriteLine(instance);
    }
    

    But in this case you can implement a custom attribute:

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class TestCaseGenericAttribute : TestCaseAttribute, ITestBuilder
    {
        public TestCaseGenericAttribute(params object[] arguments)
            : base(arguments)
        {
        }
    
        public Type[] TypeArguments { get; set; }
    
        IEnumerable 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);
        }
    }
    

    Usage:

    [TestCaseGeneric("Some response", TypeArguments = new[] { typeof(IMyInterface), typeof(MyConcreteClass) }]
    public void MyMethod_GenericCall_MakesGenericCall(string expectedResponse)
    {
        // whatever
    }
    

    And a similar customization for TestCaseSourceAttribute:

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class TestCaseSourceGenericAttribute : TestCaseSourceAttribute, ITestBuilder
    {
        public TestCaseSourceGenericAttribute(string sourceName)
            : base(sourceName)
        {
        }
    
        public Type[] TypeArguments { get; set; }
    
        IEnumerable 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);
        }
    }
    

    Usage:

    [TestCaseSourceGeneric(nameof(mySource)), TypeArguments = new[] { typeof(IMyInterface), typeof(MyConcreteClass) }]
    

提交回复
热议问题