views:

289

answers:

3

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...

[Test]
[TestCase<IMyInterface, MyConcreteClass>]
public void MyMethod_GenericCall_MakesGenericCall<TInterface, TConcreteClass>()
{
    // Arrange

    // Act
    var response = MyClassUnderTest.MyMethod<TInterface>();

    // Assert
    Assert.IsInstanceOf<TConcreteClass>(response);
}

Or if not, what is the best way to achieve the same functionality (obviously I'll have multiple TestCases in the real code)?

Update with another example...

Here is another example with a single generic type passed...

[Test]
[TestCase<MyClass>("Some response")]
public void MyMethod_GenericCall_MakesGenericCall<T>(string expectedResponse)
{
    // Arrange

    // Act
    var response = MyClassUnderTest.MyMethod<T>();

    // Assert
    Assert.AreEqual(expectedResponse, response);
}
+1  A: 

Start with the test first--even when testing. What do you want to do? Probably something like this:

[Test]
public void Test_GenericCalls()
{
    MyMethod_GenericCall_MakesGenericCall<int>("an int response");
    MyMethod_GenericCall_MakesGenericCall<string>("a string response");
      :
}

Then you can just make your test a plain old function test. No [Test] marker.

public void MyMethod_GenericCall_MakesGenericCall<T>(string expectedResponse)
{
    // Arrange

    // Act
    var response = MyClassUnderTest.MyMethod<T>();

    // Assert
    Assert.AreEqual(expectedResponse, response);
}
Ray
Although it doesn't use TestCases this seems the most appropriate way to structure this code from a readability perspective. Then downside though is that one failing instance will cause the entire test to fail and therefore won't pinpoint an error.
Russell Giddings
+1  A: 

Attributes in C# cannot be generic, so you won't be able to do things exactly as you'd like. Perhaps the easiest thing would be to put TestCase attributes onto a helper method which uses reflection to call the real method. Something like this might work (note, untested):

    [TestCase(typeof(MyClass), "SomeResponse")]
    public void TestWrapper(Type t, string s)
    {
        typeof(MyClassUnderTest).GetMethod("MyMethod_GenericCall_MakesGenericCall").MakeGenericMethod(t).Invoke(null, new [] { s });
    }
kvb
I think this is about the closest you can get using the TestCase attribute, kudos on that, but it does make the test fairly hard to read.
Russell Giddings
+1  A: 

I did something similar last week. Here's what I ended up with:

internal interface ITestRunner
{
    void RunTest(object _param, object _expectedValue);
}

internal class TestRunner<T> : ITestRunner
{
    public void RunTest(object _param, T _expectedValue)
    {
        T result = MakeGenericCall<T>();

        Assert.AreEqual(_expectedValue, result);
    }
    public void RunTest(object _param, object _expectedValue)
    {
        RunTest(_param, (T)_expectedValue);
    }
}

And then the test itself:

[Test]
[TestCase(typeof(int), "my param", 20)]
[TestCase(typeof(double), "my param", 123.456789)]
public void TestParse(Type _type, object _param, object _expectedValue)
{
    Type runnerType = typeof(TestRunner<>);
    var runner = Activator.CreateInstance(runnerType.MakeGenericType(_type));
    ((ITestRunner)runner).RunTest(_param, _expectedValue);
}
Anna Lear
Yep, in a similar vein to kvb's response this is as near as you can get in terms of the TestCase attribute and then using reflection to run the test. Like I said to kvb though, it makes it slightly taxing to understand what's being tested.
Russell Giddings
@Russell: Definitely. In my actual code, I mitigated the readability problem slightly by using clear names for the classes and methods involved.
Anna Lear