TestNG: How to test for mandatory exceptions?

30,860

Solution 1

@Test(expectedExceptions) is useful for the most common cases:

  • You expect a specific exception to be thrown
  • You need the message of that exception to contain specific words

Per the documentation a test will fail if no expectedException is thrown:

The list of exceptions that a test method is expected to throw. If no exception or a different than one on this list is thrown, this test will be marked a failure.

Here are a few scenarios where @Test(expectedExceptions) is not sufficient:

  • Your test method has several statements and only one of them is expected to throw
  • You are throwing your own type of exception and you need to make sure it matches a certain criterion

In such cases, you should just revert to the traditional (pre-TestNG) pattern:

try {
  // your statement expected to throw
  fail();
}
catch(<the expected exception>) {
  // pass
}

Solution 2

Use @Test annotation to check expected exceptions.

@Test(
    expectedExceptions = AnyClassThatExtendsException.class,
    expectedExceptionsMessageRegExp = "Exception message regexp"
)

Or if you don't want to check for exception message, only below is enough

@Test(expectedExceptions = AnyClassThatExtendsException.class)

In that way, you don't need to use ugly try catch block, just invoke you exception-thrower method inside the test.

Solution 3

I have to disagree with the the article on the nature of the testing techniques employed. The solution employs a gate, to verify if the test should succeed or fail in an intermediate stage.

In my opinion, it is better to employ Guard Assertions, especially for such tests (assuming that the test does not turn out to be long-winded and complex, which is an anti-pattern in itself). Using guard-assertions forces you to design the SUT in either of the following ways:

  • design the method itself to provide enough information in the result on whether the invocation passed or succeeded. Sometimes, this cannot be done as the intention of the designer is to not return a result, and instead throw an exception (this can be handled in the second case).
  • design the SUT so that it's state can be verified after each significant method invocation.

But before we consider the above possibilities, have a look at the following snippet again:

plane.bookAllSeats();
plane.bookPlane(createValidItinerary(), null);

If the intention is to test bookPlane() and verify for execution of that method, it is better to have bookAllSeats() in a fixture. In my understanding, invoking bookAllSeats() is equivalent to setting up the SUT to ensure that the invocation of bookPlane() fails, and hence having a fixture to do the same would make for a more readable test. If the intention are different, I would recommend testing the state after every transition (as I normally would do in functional tests), to help pinpoint the original cause of failure.

Solution 4

if you are using java 7 and testng this can be used for java 8 you can also use lambda expressions

class A implements ThrowingRunnable{


            @Override
            public void run() throws AuthenticationFailedException{
                spy.processAuthenticationResponse(mockRequest, mockResponse, authenticationContext);
            }
        }
        assertThrows(AuthenticationFailedException.class,new A());
Share:
30,860
Christopher Parker
Author by

Christopher Parker

“JavaScript jockey and Free software advocate” FSF Associate Member #795 Join the FSF as an Associate Member! Where I Am: Google Profile (contains links to dozens of other profiles) StackExchange Profiles: Stack Overflow Server Fault Super User Meta Stack Overflow Stack Apps Doctype (Yeah, I know. Get over it.) StackExchange Startups.com Basically Money MathOverflow Mozilla Labs | Concept Series CareerOverflow Chiphacker

Updated on April 06, 2020

Comments