Как я могу заставить JUnit Test ждать?

У меня есть тест 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 (как и ожидалось). Есть ли какой-то трюк, или мне нужен другой монитор?

Ответ 1

Как насчет Thread.sleep(2000);?:)

Ответ 2

Thread.sleep() может работать в большинстве случаев, но обычно, если вы ждете, вы действительно ожидаете возникновения определенного состояния или состояния. Thread.sleep() не гарантирует, что все, что вы ожидаете, на самом деле произошло.

Если вы ожидаете запроса на отдых, например, может быть, он обычно возвращается через 5 секунд, но если вы установите ваш сон в течение 5 секунд в день, когда ваш запрос вернется через 10 секунд, ваш тест будет терпеть неудачу.

Чтобы исправить это, JayWay имеет отличную утилиту под названием Awatility, которая идеально подходит для обеспечения того, чтобы какое-то конкретное условие произошло, прежде чем двигаться дальше.

У него также неплохой беглый api

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

https://github.com/jayway/awaitility

Ответ 3

Вы также можете использовать объект CountDownLatch, как описано здесь.

Ответ 4

В случае, если ваш статический анализатор кода (например, SonarQube) жалуется, но вы не можете думать о другом пути, кроме сна, вы можете попробовать взломать, как: Awaitility.await().pollDelay(Duration.ONE_SECOND).until(() → true); Это концептуально неверно, но это то же самое, что Thread.sleep(1000).

Лучший способ, конечно, это пройти Callable с вашим подходящим состоянием, а не с true, как у меня.

https://github.com/awaitility/awaitility

Ответ 5

Вы можете использовать библиотеку 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"));
}

Эта библиотека обеспечивает более четкую интерпретацию для единицы времени. Вы можете использовать "ЧАСЫ"/"МИНУТЫ"/"СЕКУНДЫ".

Ответ 6

с помощью Java с помощью wait и notify:

    @Before
    public void setup() {
        DataCache.setWhenReady(() -> {
            synchronized (this) {
                notify();
            }
        });
        try {
            synchronized (this) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

Ответ 7

Есть общая проблема: трудно издеваться над временем. Кроме того, это действительно плохая практика - помещать долго выполняющийся/ожидающий код в unit тест.

Итак, для создания тестируемого 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 и хорошей стратегии синхронизации времени.