It started as a simple TestNG idea I had while riding my bicycle on my way to playing tennis.

TestNG allows you to specify that a certain test method is expected to throw an
exception.  If the test does, then TestNG marks it as a success.  If
it fails to throw or throws a different exception than the one expected, then
TestNG will record the test as a failure.

The current syntax uses an attribute of the @Test annotation:

@Test(expectedExceptions = NumberFormatException.class)
public void shouldThrow()
{ … }

But now, I was wondering if I couldn’t replace this with:

public void shouldThrow() throws NumberFormatException
{ … }

The idea is that whenever TestNG encounters a test method that declares a
clause, it will expect that test method to throw that exception, exactly as if the developer had specified

I ran the idea by a couple of people who didn’t see anything wrong with it, so I went ahead and implemented it. The fix took two minutes and ten lines of code.

An idea that everybody likes and that takes ten lines of code… sounds like a winner, right?

Well, it was… until I ran the TestNG regression tests and noticed that a few of them failed. I investigated and found a test like this:

public void verifyFile() throws IOException {
 // test that uses File and can throw IOException

Unsurprisingly, the new TestNG expected this method to throw an IOException while the throws clause is just saying that this code could throw. Since there is no reason to declare this, I decide that I can get rid of the throws clause
as follows:


public void verifyFile() {
try {
    // test that uses File and can throw IOException
  catch(IOException ex) {


It works, but… is it wise?

First of all, the regression tests failed. This is always a red flag: if they failed, it means you just introduced a change that could break existing code.

But more importantly, it looks like I now need to handle exceptions in all my future test methods myself. Come to think of it, it’s pretty nice to be able to ignore all the possible exceptions that your test code can throw and know that TestNG will notice this and automatically fail the test, regardless of what
went wrong.

When I write a test to verify that something works well, that’s exactly what I want to focus on: everything must go as planned. If the slightest thing goes wrong, such as an unexpected exception, I want the testing framework to take care of it.

In the face of this mounting evidence, I decided that the change was not worth it and reverted my code.

Moral of the story: tests that break are trying to tell you something. 
Listen to them.