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

ExpectedException#expect() should take Matcher<? extends Throwable> as its argument #610

Closed
UrsMetz opened this issue Jan 13, 2013 · 6 comments

Comments

@UrsMetz
Copy link
Contributor

UrsMetz commented Jan 13, 2013

Consider the following test:

...
public class WrongUsageOfExpectedExceptionApi {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void wrongUsageOfExpectedExceptionApi() throws Exception {
        thrown.expect(RuntimeException.class);

        // thrown.expectMessage() should be used here
        // because an exception cannot start with a string
        thrown.expect(startsWith("some message"));
        throw new RuntimeException("some message");
    }
}
...

When you have something like this in a test it can be quite hard to figure out why the test fails.
At the moment ExpectedException#expect takes a Matcher<?> as its argument. By changing it to take only arguments of the type Matcher<? extends Throwable> the compiler could spot the mistake in the test given above.
I tried the code changes needed for the suggested change in the API with the current master (92a3f73) and all tests pass.
I understand that these changes break the API and non-generic Matchers won't work with the new signature of the method but is there any other reason not to have ExpectedException#expect only take arguments of the type Matcher<? extends Throwable>?
Apart from the exclusion of non-generic Matchers the only downside I see is that now you have to specify the generic type: That is you have to write for example

ExpectedException#expect(CoreMatchers.<Throwable>not(CoreMatchers.<Throwable>instanceOf(type)));

instead of

ExpectedException#expect(not(instanceOf(type)));
@dsaff
Copy link
Member

dsaff commented Jan 14, 2013

In my experience, getting stricter with Matcher type parameters almost always results in unexpected negative consequences, similar to the much more verbose required syntax you mention.

What is the error message thrown in the above case?

@UrsMetz
Copy link
Contributor Author

UrsMetz commented Jan 14, 2013

The error message is

java.lang.AssertionError: 
Expected: (an instance of java.lang.RuntimeException and a string starting with "some message")
     but: a string starting with "some message" was a java.lang.RuntimeException (<java.lang.RuntimeException: some message>)
...

which is correct and gives you a hint what the problem might be. But when you don't read the error message carefully you might wonder why the test isn't green.
I think the problem is that the hamcrest matcher's error message isn't that expressive because it should state explicitly that the matcher type doesn't match the type of the object it is asked to match. But on the other hand you could argue that with the stricter signature of ExpectedException#expect() the compiler would spot that mismatch of types.
Maybe a matcher wrapper for ExpectedException#expect() or something else ensuring the right type could make it easier to spot such wrong usage of the API while sticking to the current signature.
Nevertheless I still think that a stricter signature for ExpectedException#expect() should be considered: Only Matcher<? extends Throwable>s make sense for ExpectedException#expect because you can't match an exception with e.g. a Matcher<String> .

@dsaff
Copy link
Member

dsaff commented Jan 15, 2013

I'll consider it, but I'm not sure it will be worth the type pain.

@kcooney
Copy link
Member

kcooney commented May 27, 2015

@UrsMetz Note that we are considering removing our Hamcrest dependencies, so you might want to file this bug against the java-hamcrest project (https://github.com/hamcrest/hamcrest-junit).

@UrsMetz
Copy link
Contributor Author

UrsMetz commented Jul 28, 2015

@kcooney I re-raised this issue at hamcrest-junit: hamcrest/hamcrest-junit#12.
I think this issue can now be closed?

@marcphilipp
Copy link
Member

@UrsMetz Thanks!

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

4 participants