'Verifying ArgumentException and its message in Nunit , C#

In my test program in Nunit, I want to verify that it's getting the write Argument Exception by verifying the message.

    [Test]
    public void ArgumentsWorkbookNameException()
    {
        const string workbookName = "Tester.xls";
        var args = new[] { workbookName, "Sheet1", "Source3.csv", "Sheet2", "Source4.csv" };
        Assert.Throws(typeof(ArgumentException), delegate { var appargs = new ApplicationArguments(args); }, "Invalid ending parameter of the workbook. Please use .xlsx");

    }

After testing this out, this doesn't work when I modified the message in the main program.

        int wbLength = args[0].Length;

        // Telling the user to type in the correct workbook name file.
        if (args[0].Substring(wbLength-5,5)!=".xlsx")
        {
            throw new ArgumentException(
                "Invalid ending parameter of the workbook. Please use .xlsx random random");
        }

The unit test still passed, regardless if I changed the message.

How do I do it? Or is there no such things in C#. My colleague said there are options like that in Ruby and RSPEC, but he's not 100% sure on C#.



Solution 1:[1]

Use the fluent interface to create assertions:

Assert.That(() => new ApplicationArguments(args), 
    Throws.TypeOf<ArgumentException>()
        .With.Message.EqualTo("Invalid ending parameter of the workbook. Please use .xlsx random random"));

Solution 2:[2]

I agree with Jon that "such tests are unnecessarily brittle". However, there are at least two ways to check for exception message:

1: Assert.Throws returns an exception, so you can make an assertion for its message:

var exception = Assert.Throws<ArgumentException>(() => new ApplicationArguments(args));
Assert.AreEqual("Invalid ending parameter of the workbook. Please use .xlsx random random", exception.Message);

2: [HISTORICAL] Before NUnit 3, you could also use ExpectedException attribute. But, take a note that attribute waits for an exception in the whole tested code, not only in code which throws an exception you except. Thus, using this attribute is not recommended.

[Test]
[ExpectedException(typeof(ArgumentException), ExpectedMessage = "Invalid ending parameter of the workbook. Please use .xlsx random random")]
public void ArgumentsWorkbookNameException()
{
    const string workbookName = "Tester.xls";
    var args = new[] { workbookName, "Sheet1", "Source3.csv", "Sheet2", "Source4.csv" };
    new ApplicationArguments(args);
}

  1. You may also use FluentAssertions to do so, e.g.
subject.Invoking(y => y.Foo("Hello"))
       .Should().Throw<InvalidOperationException>()
       .WithMessage("Hello is not allowed at this moment");

Solution 3:[3]

The message parameter in Assert.Throws isn't the expected exception message; it's the error message to include with the assertion failure if the test fails.

I don't believe that NUnit supports testing the exception message out of the box, and I'd argue that such tests are unnecessarily brittle anyway. If you really want to write your own such helper method you can do so, but I personally wouldn't encourage it. (I very rarely specify a test failure message either, unless it's to include some diagnostic information. If a test fails I'm going to look at the test anyway, so the message doesn't add much.)

I would encourage you to use the generic overload instead though, and a lambda expression, for simplicity:

Assert.Throws<ArgumentException>(() => new ApplicationArguments(args));

(If that's your actual code by the way, there are other problems - try passing in new[] { "xyz" } as an argument...)

Solution 4:[4]

In .NET Core 3.1 MSTest project, this is how I did it.

[TestMethod]
public async Task SaveItemAsync_NameIsNull_ThrowsException()
{
    var item = new Item
    {
        Name = null
    };

    var result = await Assert.ThrowsExceptionAsync<ArgumentException>(() => _service.SaveItemAsync(item));
    Assert.AreEqual("The item's name must be set.", result.Message);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 PleasantD
Solution 2
Solution 3 Jon Skeet
Solution 4