JUnit4-FailOnTimeout.java的源代码
用于判断测试是否超时
当发生超时异常时,lookForStuckThread的作用,以及ThreadGroup这部分的处理不太了解,在这里做个标记…看将来什么时候,能看懂…插入时间戳(星期四, 17. 八月 2017 02:09上午)
删减版
FailOnTimeout
将 statement
的执行放到了一个后台线程(特点:如果没有运行的非后台线程,后台线程会被杀死,程序退出)的运行之中
使用Callable<T>
, 能够从任务(线程)中获得返回值,泛型T代表的就是方法call()返回的类型。
FutureTask
的构造函数接受Callable
,同时调用get(long timeout, TimeUnit unit)
方法能够用于判断在规定的时间内能否获取Callable返回结果。这里的timeout就是我们设置的超时时间(在@Test
中赋值,或者定义规则@Rule
或@ClassRule
)。
为了使执行时间更加精确,需要同步statement和get
方法的执行,这里使用到了CountDownLatch
。
CountDownLatch
可以设置一个初始值,任何在这个对象上调用await()方法都将阻塞,直到这个计数为0。同时通过调用countDown()来减小这个值,来触发阻塞的方法的执行。CountDownLatch只能够触发一次。
public class FailOnTimeout extends Statement {
private final Statement originalStatement;
private final TimeUnit timeUnit;
private final long timeout;
@Override
public void evaluate() throws Throwable {
CallableStatement callable = new CallableStatement();
FutureTask<Throwable> task = new FutureTask<Throwable>(callable);
threadGroup = new ThreadGroup("FailOnTimeoutGroup");
Thread thread = new Thread(threadGroup, task, "Time-limited test");
thread.setDaemon(true);
thread.start();
callable.awaitStarted();
Throwable throwable = getResult(task, thread);
if (throwable != null) {
throw throwable;
}
}
private Throwable getResult(FutureTask<Throwable> task, Thread thread) {
try {
if (timeout > 0) {
return task.get(timeout, timeUnit);
} else {
return task.get();
}
} catch (InterruptedException e) {
return e; // caller will re-throw; no need to call Thread.interrupt()
} catch (ExecutionException e) {
// test failed; have caller re-throw the exception thrown by the test
return e.getCause();
} catch (TimeoutException e) {
return createTimeoutException(thread);
}
}
private class CallableStatement implements Callable<Throwable> {
private final CountDownLatch startLatch = new CountDownLatch(1);
public Throwable call() throws Exception {
try {
startLatch.countDown();
originalStatement.evaluate();
} catch (Exception e) {
throw e;
} catch (Throwable e) {
return e;
}
return null;
}
public void awaitStarted() throws InterruptedException {
startLatch.await();
}
}
}