Certain that I missed an existing solution, I post this in hopes of helping anyone who also misses it. But if you know a better way, please comment.
Usage
class SomeTest {
@Test(timeout = 1000L)
public void shouldBlock() {
assertBlocks(new BlockingCall() {
@Override
public void call()
throws InterruptedException {
// My blocking code here
}
});
}
}
Implementation
import javax.annotation.Nonnull;
import java.util.Timer;
import java.util.TimerTask;
import static java.lang.String.format;
import static java.lang.Thread.currentThread;
import static org.junit.Assert.fail;
/**
* {@code BlockingCall} supports blocking call assertion for JUnit tests.
*
* @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
*/
public interface BlockingCall {
/**
* Calls blocking code. The blocking code must throw {@code
* InterruptedException} when its current thread is interrupted.
*
* @throws InterruptedException if interrupted.
*/
void call()
throws InterruptedException;
/** Wrapper class for block assertion. */
public static final class Assert {
/**
* Asserts the given <var>code</var> blocks at least 100ms. Interrupts
* the blocking code after 100ms and checks {@code InterruptedException}
* was thrown. When not blocking, appends <var>block</var> to the
* failure message.
*
* @param block the blocking call, never missing
*/
public static void assertBlocks(@Nonnull final BlockingCall block) {
final Timer timer = new Timer(true);
try {
final Thread current = currentThread();
timer.schedule(new TimerTask() {
@Override
public void run() {
current.interrupt();
}
}, 100L);
block.call();
fail(format("Did not block: %s", block));
} catch (final InterruptedException ignored) {
} finally {
timer.cancel();
}
}
}
}
UPDATE: Idioms like this would be far more attractive with Java 8 lambdas:
public void shouldBlock() {
assertBlocks(() -> { /* blocking code */ });
}