hamcrest / JavaHamcrest

Java (and original) version of Hamcrest
http://hamcrest.org/
BSD 3-Clause "New" or "Revised" License
2.11k stars 379 forks source link

Add declarative equivalent of JUnit's assertThrows #329

Open peterdemaeyer opened 3 years ago

peterdemaeyer commented 3 years ago

Since version 4.13, JUnit has added assertThrows, with typical JUnit style "expected first argument, actual second argument". Hamcrest does not have a declarative equivalent. As a developer, I want to have a declarative equivalent of Junit's assertThrows, so that I can consistently use Hamcrest's declarative syntax when writing unit tests.

So, given the JUnit syntax: assertThrows(Throwable.class, () -> methodThatThrows()) I would like to be able to write something like this in Hamcrest syntax: assertThat(() -> methodThatThrows(), throws(instanceOf(Throwable.class))); Of course, throws is a reserved keyword in Java, so that would have to become for example doesThrow instead.

peterdemaeyer commented 3 years ago

The functionality I desire could really benefit from Java 1.8 lambda expressions, while Hamcrest is still on Java 1.7. I'll prepare a fix for Java 1.7 nonetheless.

peterdemaeyer commented 3 years ago

I've prepared a fix that adds the desired functionality.

Illustration of use (using Java 1.8 lambda expressions):

assertThat(() -> methodCallThatThrowsException(), doesThrow(instanceOf(Exception.class));
// Shorthand for the above
assertThat(() -> methodCallThatThrowsException(), throwsInstanceOf(Exception.class));
// Match throwable's cause rather than throwable itself
assertThat(() -> methodCallThatThrowsExceptionWithCause(), doesThrow(becauseOf(instanceOf(CauseException.class)));
// Match throwable's message
assertThat(() -> methodCallThatThrowsExceptionWithMessage(), doesThrow(withMessage(startsWith("start of message"))));
peterdemaeyer commented 3 years ago

I created a PR for my changes, but it doesn't link correctly. Not sure what is wrong, I could use some guidance here.