如何进行JUnit测试等待?


93

我有一个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(如预期的那样)。是否有一些技巧,还是我需要其他显示器?

Answers:



71

Thread.sleep()在大多数情况下都可以工作,但是通常,如果您在等待,则实际上是在等待特定条件或状态的发生。Thread.sleep()不保证您正在等待的一切实际上已经发生。

例如,如果您正在等待休息请求,则通常会在5秒钟后返回,但是如果您将睡眠时间设置为5秒钟,则您的请求在10秒钟后又回来的那一天,您的测试将会失败。

为了解决这个问题,JayWay有一个称为Awatility的强大实用程序,非常适合确保在继续前进之前发生特定情况。

它也有一个很好的流利的api

await().until(() -> 
{
    return yourConditionIsMet();
});  

https://github.com/jayway/awaitility


我无法等待在Android Studio中进行编译。
IgorGanapolsky '16

您是否将此行添加到gradle文件中:编译'org.awaitility:awaitility:3.0.0'?
Samoht

没有。您可以将其添加到要等待特定条件的测试用例中
Ben Glasser

15

如果您的静态代码分析器(例如SonarQube)投诉,但您无法想到另一种方法,而不是睡觉,您可以尝试使用类似的方法: Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true); 在概念上不正确,但与相同Thread.sleep(1000)

当然,最好的方法是传递一个具有您适当条件的Callable,而不是true我拥有的。

https://github.com/awaitility/awaitility


@Jitendra:请注意,Awaitility曾经有Duration该类,但是从版本4开始,他们将其重命名为Durations
Jacob van Lingen

请注意,如果您希望轮询延迟为10秒或更长,请确保将超时增加到10秒以上,因为这是默认超时,并且等待时间会抱怨超时小于轮询延迟。
将焦点集中

12

您可以使用java.util.concurrent.TimeUnit库,该库在内部使用Thread.sleep。语法应如下所示:

@Test
public void testExipres(){
    SomeCacheObject sco = new SomeCacheObject();
    sco.putWithExipration("foo", 1000);

    TimeUnit.MINUTES.sleep(2);

    assertNull(sco.getIfNotExipred("foo"));
}

该库为时间单位提供了更清晰的解释。您可以使用“小时” /“分钟” /“秒”。


如果我从测试中启动工作线程,会sleep()影响工作线程吗?
Anthony Kong


0

有一个普遍的问题:很难模拟时间。另外,在单元测试中放置长时间运行/等待的代码确实是一种不好的做法。

因此,为了使Schedule 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引用和良好的时间同步策略来实现。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.