Search code examples
javaunit-testingjunithamcrest

Custom hamcrest matcher that works with "not"?


I have some class (say, Entity).

I want to be able to

  1. test that an instance of that is "valid", using some custom code to decide that
  2. also test that an instance is not valid, ideally using the same code.

Using maven, surefire, JUnit 4.11 (and the hamcrest stuff shipped with it).

So I write a class something like this

class IsValidEntity extends TypeSafeMatcher<Entity>{

    @Override public boolean matchesSafely(Entity e){
       // and here I do a bunch of asserts...
       assertNotNull(e.id);
       // etc.
    }

    @Override
    public void describeTo(Description description) {
       description.appendText("is valid entity");
    }

    @Factory
    public static <T> Matcher<Entity> validEntity() {
        return new IsValidEntity();
    } 
}

OK, fine, I can then do

assertThat(entity, is(validEntity()); 

in a JUnit test, peachy.

But I can't do

assertThat(entity, not(validEntity());

because the validEntity fails with broken asserts, while for not I guess it should just return false.

Clearly I'm doing something backwards here but I'm not sure what's the most clever way of doing these custom matchers. Or maybe I shouldn't be using TypeSafeMatcher at all but doing something different?


Solution

  • Your matchesSafely method should be rewritten to avoid throwing assertion failures. Instead, just perform the checks manually and then return false if necessary.

    Then, you can negate it in the manner you desire without consequence.