Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add declarative equivalent of JUnit's assertThrows #329

Open
peterdemaeyer opened this issue Feb 21, 2021 · 3 comments
Open

Add declarative equivalent of JUnit's assertThrows #329

peterdemaeyer opened this issue Feb 21, 2021 · 3 comments

Comments

@peterdemaeyer
Copy link

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
Copy link
Author

peterdemaeyer commented Feb 21, 2021

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 added a commit to peterdemaeyer/JavaHamcrest that referenced this issue Feb 21, 2021
peterdemaeyer added a commit to peterdemaeyer/JavaHamcrest that referenced this issue Feb 21, 2021
@peterdemaeyer
Copy link
Author

peterdemaeyer commented Feb 21, 2021

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

  • Added <T extends Throwable> MatcherAssert.assertThat(String reason, Executable executable, Throws<T> doesThrow).
  • Added similar convenience method without reason.
  • Executable is similar to JUnit's class with the same name, but I gave Hamcrest its own not to be tied down to a JUnit-specific dependency and in addition Hamcrest's is not a @FunctionalInterface because it needs to be Java 1.7 compliant.
  • To avoid signature conflicts with other assertThat methods, Throws is not a Matcher itself, but is a distinct type.
  • Added multiple factory methods for throwable matchers to Matchers, backed by a Throws class, in line with Hamcrest design, like doesThrow, throwsInstanceOf etc.
  • Settled for doesThrow because throws is a reserved Java keyword.
  • Took great care to make sure the descriptive phrasing of matches and mismatches is on par with Hamcrest's standards.
  • Added Javadoc + new unit tests covering the new behavior.

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
Copy link
Author

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

peterdemaeyer added a commit to peterdemaeyer/JavaHamcrest that referenced this issue Feb 21, 2021
peterdemaeyer added a commit to peterdemaeyer/JavaHamcrest that referenced this issue Dec 26, 2021
peterdemaeyer added a commit to peterdemaeyer/JavaHamcrest that referenced this issue Dec 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant