作为TDD从业者,我想测试我编码的所有内容。
在过去的几年里,我一直在编写许多多线程代码,而且我的测试中有一部分一直困扰着。
当我必须断言在 run()循环期间可能发生的事情时,我最终会得到某种类似的断言:
assertEventually(timeout, assertion)
我知道Mockito有一个解决方案,但仅适用于验证调用。我也知道 JUnit 有一个超时属性,可以避免挂起(或永久)测试。但我想要的是能够让我断言可能随着时间的推移变成真实的东西。
所以我的问题是,有没有人知道提供此功能的库?
到目前为止,这是我的解决方案:
private void assertEventually(int timeoutInMilliseconds, Runnable assertion){
long begin = System.currentTimeMillis();
long now = begin;
Throwable lastException = null;
do{
try{
assertion.run();
return;
}catch(RuntimeException e){
lastException = e;
}catch(AssertionError e){
lastException = e;
}
now = System.currentTimeMillis();
}while((now - begin) < timeoutInMilliseconds);
throw new RuntimeException(lastException);
}
使用它最终会像这样:
assertEvetuallyTrue(1000, new Runnable() {
public void run() {
assertThat(Thread.activeCount()).isEqualTo(before);
}
});
答案 0 :(得分:3)
您可能想要查看的两个图书馆:
答案 1 :(得分:1)
从你使用的语言 - 断言某些事情可能是真的 - 听起来你走的路会导致脆弱的测试。测试应该有二元结果 - 它们要么通过要么失败,而且没有灰色区域。
看一下这个具体的例子,考虑到使用多线程,我会建议这样的事情:
以这种方式拆分测试的另一个优点是,您可以为单元测试和系统测试创建单独的测试套件,这有助于保持您的单元测试套件快速且精简(因此您可以更轻松,更经常地运行它)发展)。任何涉及超时的测试(即本例中的系统测试)都需要更长的时间来执行,因此更适合仅偶尔运行 - 这种方法使这更容易。
答案 2 :(得分:1)
如果您来自Scala,您可能会习惯于eventually特征。
它对测试非常有用,因为您可以重试一段时间,直到最终返回结果为止。
这里有 halfvim 制作的Java包装器:https://github.com/halfvim/eventually
答案 3 :(得分:0)
及时性测试是一种性能测试,除非您有实时性要求,否则会对许多样本进行统计。
单元测试只关注单个样本,它们应该是确定性的。而不是这个检查和循环结构,我认为你应该通过某种机制通知你的JUnit线程,只要你想要断言的事件发生。回调,期货,锁存,交易所等可以用来建立这样的机制。
构建多线程代码是一项设计挑战,因此可以在没有检查和循环的情况下对其进行测试,或者在状态上进行旋转等待。
但是如果你真的必须这样做,那么使用System.nanoTime()
代替System.currentTimeMillis()
因为它更频繁地更新,尽管两个时钟的实际实现和准确性取决于你的JVM版本,操作系统和硬件。