JUnit 테스트를 기다리려면 어떻게해야합니까?


94

동 기적으로 일정 시간 동안 기다리려는 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이 발생 합니다.

트릭이 있습니까 아니면 다른 모니터가 필요합니까?

답변:


118

어때요 Thread.sleep(2000);? :)


15
sonarqube와 같은 코드 분석 도구를 사용하는 경우 테스트에서 Thread.sleep을 사용하는 것은 일반적으로 나쁜 생각Thread.sleep 이라고 불평 할 것 입니다. 환경 ( "내 머신에 합격!") 또는 부하에 따라 예상치 않게 실패 할 수있는 취성 테스트를 생성합니다. 비동기 테스트를 위해 타이밍에 의존하거나 (모의 사용) Awaitility와 같은 라이브러리를 사용하지 마십시오.
FuryFart

4
이 대답은 제거되어야하며 유해한 것으로 간주되어야합니다. 아래의 훨씬 더 나은 대답은 stackoverflow.com/a/35163873/1229735
yiati

73

Thread.sleep ()은 대부분의 경우에 작동 할 수 있지만 일반적으로 기다리는 경우 실제로 특정 조건이나 상태가 발생하기를 기다리고 있습니다. Thread.sleep ()은 당신이 기다리는 것이 실제로 일어 났음을 보장하지 않습니다.

예를 들어 휴식 요청을 기다리는 경우 일반적으로 5 초 후에 반환되지만 수면을 5 초로 설정하면 요청이 10 초 후에 다시 돌아 오는 날 테스트가 실패합니다.

이 문제를 해결하기 위해 JayWay에는 진행 하기 전에 특정 상태가 발생하도록 보장하는 Awatility 라는 훌륭한 유틸리티 가 있습니다.

유창한 API도 있습니다.

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

https://github.com/jayway/awaitility


Android Studio에서 컴파일 대기를 할 수 없었습니다.
IgorGanapolsky

gradle 파일에 다음 줄을 추가 했습니까? compile 'org.awaitility : awaitility : 3.0.0'?
Samoht

아니. 특정 조건
Ben Glasser

16

정적 코드 분석기 (예 : SonarQube)가 불만을 제기하지만 잠자기보다는 다른 방법을 생각할 수없는 경우 다음과 같은 해킹을 시도 할 수 있습니다. Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true); 개념적으로 잘못되었지만 Thread.sleep(1000).

물론 가장 좋은 방법은 true내가 가지고있는 대신 적절한 조건으로 Callable을 전달하는 것입니다.

https://github.com/awaitility/awaitility


@Jitendra : Awaitility는 이전에 Duration클래스 를 가지고 있었지만 버전 4부터는 Durations.
Jacob van Lingen

한 가지주의 할 점은 폴링 지연이 10 초 이상이되도록하려면 기본 타임 아웃이고 대기 성은 타임 아웃이 폴 지연보다 작다고 불평 할 것이므로 타임 아웃을 10 초 이상으로 늘려야합니다.
포커스

14

내부적으로 Thread.sleep을 사용하는 java.util.concurrent.TimeUnit 라이브러리를 사용할 수 있습니다. 구문은 다음과 같습니다.

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

    TimeUnit.MINUTES.sleep(2);

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

이 라이브러리는 시간 단위에 대한보다 명확한 해석을 제공합니다. 'HOURS'/ 'MINUTES'/ 'SECONDS'를 사용할 수 있습니다.


테스트 내에서 작업자 스레드를 시작하면 작업자 스레드에 sleep()영향을 줍니까?
Anthony Kong


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, 예를 들어 참조 및 좋은 시간 동기화 전략을 사용하여 만들 수 있습니다 .


0

테스트에서 지연을 생성하는 것이 절대적으로 필요하다면 CountDownLatch간단한 해결책입니다. 테스트 클래스에서 다음을 선언하십시오.

private final CountDownLatch waiter = new CountDownLatch(1);

필요한 경우 테스트에서 :

waiter.await(1000 * 1000, TimeUnit.NANOSECONDS); // 1ms

말할 필요도 없을 수도 있지만 대기 시간을 작게 유지하고 너무 많은 장소에 대기를 누적하지 않아야한다는 점을 명심하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.