71

I am writing some unit tests with NUnit 3.0 and, unlike v2.x, ExpectedException() has been removed from the library.

Based on this answer, I can definitely see the logic in trying to catch specifically where in the test one expects their system to throw an exception (rather than just saying 'anywhere in the test').

However, I tend to be very explicit about my Arrange, Act, and Assert steps and this makes it a challenge.

I used to do something like:

[Test, ExpectedException(typeof(FormatException))]
public void Should_not_convert_from_prinergy_date_time_sample1()
{
    //Arrange
    string testDate = "20121123120122";

    //Act
    testDate.FromPrinergyDateTime();

    //Assert
    Assert.Fail("FromPrinergyDateTime should throw an exception parsing invalid input.");
}

Now I need to do something like:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    //Arrange
    string testDate = "20121123120122";

    //Act/Assert
    Assert.Throws<FormatException>(() => testDate.FromPrinergyDateTime());
}

This isn't terrible, but muddies the Act and Assert, in my opinion. (Obviously, for this simple test, it's not hard to follow, but might be more challenging in larger tests).

I've had a colleague suggest I get rid of Assert.Throws altogether and just do something like:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample3()
{
    //Arrange
    int exceptions = 0;
    string testDate = "20121123120122";

    //Act
    try
    {
        testDate.FromPrinergyDateTime();
    }
    catch (FormatException) { exceptions++;}

    //Assert
    Assert.AreEqual(1, exceptions);
}

Here, I stick with the strict AAA format, but at the expense of even more bloat.

So my question goes out to AAA-style testers: How would you do some sort of exception validation testing like I am trying to do here?

d219
  • 2,707
  • 5
  • 31
  • 36
Killnine
  • 5,728
  • 8
  • 39
  • 66
  • 1
    When tested method has no parameters the Assert can be simplified like this: Assert.Throws(testDate.FromPrinergyDateTime) or Assert.That(testDate.FromPrinergyDateTime, Throws.TypeOf()); – user3285954 Dec 05 '16 at 16:15
  • Second part doesn't look that bloated to me? – Andrew Day Jan 29 '18 at 21:41

3 Answers3

68

I see where you're coming from, even though I don't mind combining Act/Assert steps in this case.

The only thing I can think of is to store the actual delegate (here to FromPrinergyDateTime) into a variable as the "act" step and then assert it:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    //Arrange
    string testDate = "20121123120122";

    //Act
    ActualValueDelegate<object> testDelegate = () => testDate.FromPrinergyDateTime();

    //Assert
    Assert.That(testDelegate, Throws.TypeOf<FormatException>());
}

I get that the "act" step isn't really acting, but rather defining what the action is. However, it does clearly delineate what action is being tested.

Bjorn Reppen
  • 22,007
  • 9
  • 64
  • 88
Patrick Quirk
  • 23,334
  • 2
  • 57
  • 88
  • Ahh, that's pretty slick idea. I was getting hung up on how to separate the two. – Killnine Nov 24 '15 at 15:52
  • 2
    Still not really "acting" though. Just declaring how you plan to act. – JamesFaix Mar 03 '16 at 16:45
  • It's a great answer. I had a [follow-up question](http://stackoverflow.com/questions/39660806/how-to-handle-multiple-exception-testing-in-nunit-3-according-to-arrage-act-asse) to it, which I posted separately. Care to take a look? – Konrad Viltersten Sep 24 '16 at 09:02
27

In C# 7, there is another option (albeit very similar to the existing answers):

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    void CheckFunction()
    {
        //Arrange
        string testDate = "20121123120122";

        //Act
        testDate.FromPrinergyDateTime();
    }

    //Assert
    Assert.Throws(typeof(Exception), CheckFunction);
}

Blog post on the subject

Paul Michaels
  • 16,185
  • 43
  • 146
  • 269
6

You can create a custom Attribute in NUnit 3. Here is the sample code how to create [ExpectedException] Attribute.(ExpectedExceptionExample Shows how to implement a custom attribute for NUnit) https://github.com/nunit/nunit-csharp-samples

d219
  • 2,707
  • 5
  • 31
  • 36
Matt Allen
  • 492
  • 5
  • 12
  • This is exactly what I was looking for, thanks for the link! – crabCRUSHERclamCOLLECTOR Nov 05 '18 at 19:39
  • [ExpectedException] is deprecated in NUnit3. Use the Assert.That/Throws mechanism. – RvdK Mar 04 '20 at 10:52
  • @RvdK Can you please let me know what is the difference between Assert.That and Assert.Throws.. I dont really get the difference between both statements as below. Both works for me.. But which is better to use. `Assert.Throws(TestDelegate code, "Message");` `Assert.That(TestDelegate code, Is.TypeOf(), "Message"); ` – VSanka Jul 28 '20 at 06:48
  • @VikranthSanka Assert.That has better readability, the Assert.That reads more natural. But it also has some other benefits: https://objectpartners.com/2013/09/18/the-benefits-of-using-assertthat-over-other-assert-methods-in-unit-tests/ – RvdK Jul 29 '20 at 11:21