Working on a test depending on an external Ldap server (yeah, I know, this sounds bad, but sometimes you just want to make sure your code works against the real thing, not only embedded servers, such as the excellent Apache DS — which I use for other integration tests though!!!) I wanted to make sure this test would not fail when this server was down.
I wanted to tell Junit4 to skip the whole test class if I could not reach the server during an @BeforeClass method.
But how could I tell Junit4 to fail because of a condition in an @BeforeClass method ?
This is when I got 2 precious pieces of advice from my colleague (and hamcrest lover) Chris :
- use org.junit.Assume.assumeThat(T actual, Matcher<T> matcher)
- and eventually create a custom matcher
let’s have a look at the first version of the code :
1 2 3 4 5 |
@BeforeClass public static void checkServerIsOnline() throws IOException { InetAddress address = InetAddress.getByAddress(new byte[]{42, 42, 42, 42}); Assume.assumeThat(address.isReachable(5000), IsEqual.equalTo(true)); } |
so if the server is not responding after 5 secs, the test class won’t go further, and return without failing or returning an error; great !
But we can do better than that… what about :
1 2 3 4 5 |
@BeforeClass public static void checkServerIsOnline() throws IOException { InetAddress address = InetAddress.getByAddress(new byte[]{42, 42, 42, 42}); Assume.assumeThat(address, IsReachable.isReachable(5000)); } |
we have now to create the IsReachable matcher :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
public class IsReachable extends TypeSafeMatcher<InetAddress> { private final int timeout; public IsReachable(int timeout) { this.timeout = timeout; } @Override public boolean matchesSafely(InetAddress item) { try { return item.isReachable(timeout); } catch (IOException e) { e.printStackTrace(); } return false; } @Override public void describeTo(Description description) { description.appendValue(timeout); } /** * Is the address reachable as per * {@link java.net.InetAddress#isReachable(int)} ? */ @org.hamcrest.Factory public static Matcher<InetAddress> isReachable(int timeout) { return new IsReachable(timeout); } } |
Did you notice I extended a TypeSafeMatcher and not a plain Matcher ? that way I could avoid casting an Object into an InetAddress in the matches[Safely] method !