junit-team/junit — pull request #1055 by seanjreilly (2014-12-29 03:04:22+00:00)
Title: A new method to expect a thrown exception

There are generally two techniques for testing that a method throws an exception in a certain scenario.

The original technique is to use a try catch block:

```java
@Test
public void someTest() throws Exception {
//some setup here
try {
doSomethingThatThrows();
fail("expected a NullPointerException");
} catch (NullPointerException e) {
//optionally assert something about the exception
}
}
```

This method is generally not preferred because it is verbose, and error-prone. Forgetting the `fail` statement is a really subtle failure case that can be easy to miss.

The newest method is to use the `expected` element of the `@Test` annotation:

```java
@Test(expected=NullPointerException.class)
public void someTest() throws Exception {
//some setup here

doSomethingThatThrows();
}
```

This method is less verbose, and much less complicated. However, it also has two significant drawbacks that are easy to overlook:

1. You cannot make any assertions about the exception once you encounter it.
2. If the specified exception is thrown *anywhere* in the test, the test will pass, even if the test isn't thrown from the expected statement.

In the above example, if a NullPointerException is thrown in the ```//some setup here`` block, the test will still pass!

This patch adds an additional way of testing for thrown exceptions:

```java
@Test(expected=NullPointerException.class)
public void someTest() throws Exception {
//some setup here

NullPointerException e = expect(NullPointerException.class, () -> doSomethingThatThrows());

//optionally assert something about the exception
}
```

This mitigates the weaknesses of using the `expected` element of the `@Test` annotation: the exception must be thrown by calling `doSomethingThatThrows()`, or the test will fail; and the test can make assertions about the NullPointerException once it occurs.

This patch has been coded in such a way that it will compile and work with anonymous interface implementations in Java 5 or higher, although Java 8 lambda expressions are needed for the syntax to really be an improvement over the original pattern.

If no exceptions is thrown by the provided code block, then an `AssertionError` is thrown. If an exception other than the expected exception is thrown, then it will be rethrown by the `expect` method, which will cause the test to fail.