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 */ }); }
No comments:
Post a Comment