11

I want to upgrade from NUNIT 2.x to 3.x but i have tests like

[TestCase("12345", ExpectedResult = "SUCCESS")]
[TestCase("invalidkey", ExpectedException = typeof(ArgumentException))]
[TestCase(null, ExpectedException = typeof(ArgumentNullException))]
public string ReturnsStatus(string filePath)
{
    // Arrange

    // Act
    Tuple<string, string> result = service.Create(filePath);

    // Assert
    return result.Item1;
}

How to rewrite this kind of tests? NUNIT 3.x does not have ExpectedException, that is my refactorization reason. I dont want to split into 3 tests. Thanks.

Jake Manet
  • 1,174
  • 3
  • 15
  • 26
  • Possible duplicate of [Testing for exceptions with \[TestCase\] attribute in NUnit 3?](https://stackoverflow.com/questions/35061336/testing-for-exceptions-with-testcase-attribute-in-nunit-3) – Chris Feb 16 '18 at 13:18

3 Answers3

12

This is an old question, but any way...

As it was mentioned, ExpectedException is considered as a bad practice, since you can't be sure what exact part of your test throws exception (in your code it can be Create(), or get_Item1()).

However, you don't need to write separate test-method for every single case. In most situations (and in your example) it's enougth to split for two tests: positive and negative. Positive case can remain unchanged. Negative case can use type of expected exception as parameter, so that:

[TestCase("",  typeof(ArgumentException))]
[TestCase(null, typeof(ArgumentNullException))]
public void ReturnStatusInvalidArgument(string filePath, Type expectedException)
{
    Assert.Throws(expectedException, () => Method(filePath));
}

Or if you prefer "ExpectedResult" style, then you can use following

    [TestCase("", ExpectedResult = typeof(ArgumentException))]
    [TestCase(null, ExpectedResult = typeof(ArgumentNullException))]
    public Type ReturnStatusInvalidArgument(string filePath)
    {
        return Assert.Catch(() => Method(filePath)).GetType();
    }
Pavlo K
  • 837
  • 9
  • 15
  • is there any possibility to match message returned from exception ? in my scneraio i have same exception but with different messages – Salman Nov 13 '19 at 17:48
  • i have sorted it by getting message property of exception then match in expected result for different messages . I jsut want to know is it rite way of doing it ? – Salman Nov 13 '19 at 17:57
  • Assert.Catch (2-nd approach) returns appropriate exception instance. Instead of GetType() you can get Message – Pavlo K Nov 13 '19 at 18:43
8

As you discovered, NUnit 3 removed ExpectedExceptionAttribute and the related properties on TestCaseAttribute and TestCaseData.

This was done after a lot of community discussion, with less than 100% agreement but with most people recognizing that broad detection of exceptions at the level of the entire test constitutes an anti-pattern. Your example actually represents the one case where it isn't such a bad practice: a test method with only one statement. Unfortunately, you are affected by the change as well.

Two recommendations:

  1. Separate tests for "happy path" and errors.
  2. Use Assert.Throws or Assert.That(..., Throws...) for the error test.
sergtk
  • 10,714
  • 15
  • 75
  • 130
Charlie
  • 12,928
  • 1
  • 27
  • 31
1

I think "one method==one test" is best practise:

[TestCase("12345", ExpectedResult = "SUCCESS")]
public string ReturnStatusTest_SUCCESS()
{
    return ReturnsStatus("12345");
}
[TestCase("invalidkey", ExpectedException = typeof(ArgumentException))]
public string ReturnStatusTest_SUCCESS()
{
    return ReturnsStatus("invalidkey");
}
[TestCase(null, ExpectedException = typeof(ArgumentNullException))]
public string ReturnStatusTest_SUCCESS()
{
    return ReturnsStatus(null);
}

public string ReturnsStatus(string filePath)
{
    // Arrange

    // Act
    Tuple<string, string> result = service.Create(filePath);

    // Assert
    return result.Item1;
}
kara
  • 3,205
  • 4
  • 20
  • 34