In honor of this exciting occasion, I wanted to post an example. Here is the class I'm going to test:
public class PositiveInteger {
private int num;
public PositiveInteger(int num) {
if(num <= 0) {
throw new IllegalArgumentException("Number must be positive");
}
this.num = num;
}
}
Let's test -- hmmm -- the constructor, I guess. I created two test cases -- one which passes, and one which intentionally fails (just to show the resulting output):
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class TestPositiveNumber {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testConstructorInvalid_PASS() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Number must be positive");
new PositiveInteger(-5);
}
/**
* Intentionally-failing test to demonstrate the results
* when checking an exception message.
*/
@Test
public void testConstructorInvalid_FAIL() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Not gonna pass");
new PositiveInteger(-5);
}
}
JUnit now supports a style embodied in "rules", which get marked with the @Rule annotation and provide a means by which the test execution behavior can be modified. You can see that here with the "thrown" field, of type "ExpectedException". It would be great if a) that field didn't have to be public, and b) the functionality could be implemented using a local variable, but unfortunately the Java language won't currently support such an implementation. So a public field it is. In a test, you can configure the rule. Here I do that with calls to the "expect" and "expectMessage" methods. When JUnit executes the test case, it checks the result against the rule and fails if the rule is not matched. In the test case that does not pass, the failure takes this form:
java.lang.AssertionError:
Expected: (exception with message a string containing "Not gonna pass" and an instance of java.lang.IllegalArgumentException)
got:
at org.junit.Assert.assertThat(Assert.java:778)
at org.junit.Assert.assertThat(Assert.java:736)
Very useful. Thanks to Kent Beck for adding this support.