我有一个JUnit测试,我想要等待一段时间,同步。我的JUnit测试看起来像这样:
@Test
public void testExipres(){
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
//WAIT FOR 2 SECONDS
assertNull(sco.getIfNotExipred("foo"));
}
我尝试了Thread.currentThread()。wait(),但它抛出了IllegalMonitorStateException(如预期的那样)。是否有一些技巧,或者我需要一个不同的显示器?
答案 0 :(得分:107)
Thread.sleep(2000);
怎么样? :)
答案 1 :(得分:49)
Thread.sleep()在大多数情况下都可以工作,但通常如果您正在等待,您实际上正在等待某个特定条件或状态发生。 Thread.sleep()并不能保证您等待的任何事情确实发生了。
如果您正在等待休息请求,例如它通常会在5秒内返回,但如果您在10秒内将请求恢复为5秒钟,那么您的测试将会失败。
为了解决这个问题,JayWay有一个很棒的实用工具Awatility,它非常适合在你继续前进之前确保特定情况发生。
它还有一个很好的流畅api
await().until(() ->
{
return yourConditionIsMet();
});
答案 2 :(得分:4)
您也可以像解释here一样使用CountDownLatch
对象。
答案 3 :(得分:2)
如果您的静态代码分析器(如SonarQube)投诉,但您无法想到另一种方法,除了睡觉,您可以尝试以下黑客:
Awaitility.await().pollDelay(Duration.ONE_SECOND).until(() -> true);
从概念上讲这是不正确的,但与Thread.sleep(1000)
相同。
当然,最好的方法是传递具有适当条件的Callable而不是我拥有的true
。
答案 4 :(得分:2)
您可以使用java.util.concurrent.TimeUnit库,该库在内部使用Thread.sleep。语法应如下所示:
@click.native.prevent
该库为时间单位提供了更清晰的解释。您可以使用“小时” /“分钟” /“秒”。
答案 5 :(得分:2)
如果绝对必须在测试CountDownLatch
中产生延迟,则这是一个简单的解决方案。在测试类中声明:
private final CountDownLatch waiter = new CountDownLatch(1);
,并在需要的地方进行测试:
waiter.await(1000 * 1000, TimeUnit.NANOSECONDS); // 1ms
也许不必多说,但要记住,应将等待时间保持在很小的范围内,而不要将等待时间累积到太多地方。
答案 6 :(得分:0)
有一个普遍的问题:很难模拟时间。另外,在单元测试中放置长时间运行/等待的代码确实是一种不好的做法。
因此,为了使调度API可测试,我使用了具有真实和模拟实现的接口,如下所示:
public interface Clock {
public long getCurrentMillis();
public void sleep(long millis) throws InterruptedException;
}
public static class SystemClock implements Clock {
@Override
public long getCurrentMillis() {
return System.currentTimeMillis();
}
@Override
public void sleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
}
public static class MockClock implements Clock {
private final AtomicLong currentTime = new AtomicLong(0);
public MockClock() {
this(System.currentTimeMillis());
}
public MockClock(long currentTime) {
this.currentTime.set(currentTime);
}
@Override
public long getCurrentMillis() {
return currentTime.addAndGet(5);
}
@Override
public void sleep(long millis) {
currentTime.addAndGet(millis);
}
}
这样,您可以在测试中模仿时间:
@Test
public void testExipres() {
MockClock clock = new MockClock();
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
clock.sleep(2000) // WAIT FOR 2 SECONDS
assertNull(sco.getIfNotExpired("foo"));
}
当然,Clock
的高级多线程模拟要复杂得多,但是您可以使用ThreadLocal
引用和良好的时间同步策略来实现它。