JUnit testini nasıl bekletebilirim?


95

Eşzamanlı olarak bir süre beklemek istediğim bir JUnit testim var. JUnit testim şöyle görünüyor:

@Test
public void testExipres(){
    SomeCacheObject sco = new SomeCacheObject();
    sco.putWithExipration("foo", 1000);
    // WAIT FOR 2 SECONDS
    assertNull(sco.getIfNotExipred("foo"));
}

Denedim Thread.currentThread().wait(), ancak bir IllegalMonitorStateException (beklendiği gibi) atıyor .

Bunun için bir numara var mı yoksa farklı bir monitöre ihtiyacım var mı?

Yanıtlar:


119

Nasıl olur Thread.sleep(2000);? :)


15
Sonarqube gibi kod analizi araçlarını kullanıyorsanız , bir testte Thread.sleep kullanmakThread.sleep gibi bir şey söylemekten şikayet edeceklerdir . Genellikle kötü bir fikirdir. Ortama ("Makinemden geçer!") Veya yüke bağlı olarak beklenmedik şekilde başarısız olabilen kırılgan testler oluşturur. Zamanlamaya güvenmeyin (taklitler kullanın) veya eşzamansız testler için Bekleme gibi kitaplıkları kullanmayın.
FuryFart

4
Bu cevap kaldırılmalı ve zararlı kabul edilmelidir. Aşağıda çok daha iyi bir cevap stackoverflow.com/a/35163873/1229735
yiati

73

Thread.sleep () çoğu durumda işe yarayabilir, ancak genellikle bekliyorsanız, aslında belirli bir durumun veya durumun oluşmasını bekliyorsunuz. Thread.sleep (), beklediğiniz şeyin gerçekte olduğunu garanti etmez.

Örneğin dinlenme isteği bekliyorsanız, belki genellikle 5 saniye içinde geri döner, ancak uykunuzu 5 saniye için ayarlarsanız, isteğiniz 10 saniye sonra geri gelirse, testiniz başarısız olur.

Bu JayWay düzeltmek için denilen büyük yarar vardır Awatility Devam etmeden önce belirli bir koşul oluştuğunda sağlamak için idealdir.

Aynı zamanda güzel bir akıcı API'ye sahiptir

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

https://github.com/jayway/awaitility


Android Studio'da derlemek için bekleyemedim.
IgorGanapolsky

Bu satırı gradle dosyanıza eklediniz mi: 'org.awaitility: awaitility: 3.0.0' derleyin?
Samoht

Hayır. Bunu, belirli bir durumu beklemek istediğiniz bir test senaryosuna eklersiniz
Ben Glasser

16

Statik kod çözümleyiciniz (SonarQube gibi) şikayet ediyorsa, ancak uyumaktan başka bir yol düşünemiyorsanız, şöyle bir hack ile deneyebilirsiniz: Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true); Kavramsal olarak yanlış, ama aynı Thread.sleep(1000).

Elbette en iyi yol, truebenim sahip olduğumdan ziyade uygun koşulunuzla bir Çağrılabilir'i geçmektir .

https://github.com/awaitility/awaitility


@Jitendra: Awaitility'nin Durationsınıfa sahip olduğunu, ancak sürüm 4'ten beri sınıfın adını aldığını unutmayın Durations.
Jacob van Lingen

Bir uyarı, yoklama gecikmesinin 10 saniye veya daha fazla olmasını istiyorsanız, zaman aşımını 10 saniyenin üzerine çıkardığınızdan emin olun, çünkü bu varsayılan zaman aşımıdır ve bekleme, zaman aşımının yoklama gecikmesinden daha az olduğundan şikayet eder.
Odak

15

Dahili olarak Thread.sleep kullanan java.util.concurrent.TimeUnit kitaplığını kullanabilirsiniz. Sözdizimi şu şekilde görünmelidir:

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

    TimeUnit.MINUTES.sleep(2);

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

Bu kütüphane, zaman birimi için daha net yorum sağlar. "HOURS" / "MINUTES" / "SECONDS" kullanabilirsiniz.


Bir testin içinden bir çalışan iş parçacığı başlatırsam, sleep()bu işçi iş parçacığını etkiler mi?
Anthony Kong


0

Genel bir sorun var: Zamanla dalga geçmek zor. Ayrıca, uzun çalışma / bekleme kodunu bir birim testine yerleştirmek gerçekten kötü bir uygulamadır.

Bu nedenle, bir programlama API'sini test edilebilir hale getirmek için, gerçek ve şunun gibi sahte bir uygulamaya sahip bir arayüz kullandım:

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);
    }

}

Bununla, testinizde zamanı taklit edebilirsiniz:

@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"));
}

Gelişmiş bir çoklu iş parçacığı Clockmodeli elbette çok daha karmaşıktır, ancak bunu ThreadLocalörneğin referanslar ve iyi bir zaman senkronizasyonu stratejisi ile yapabilirsiniz.


0

Bir testte gecikme yaratmak mutlak bir zorunluluksa CountDownLatchbasit bir çözümdür. Test sınıfınızda şunları beyan edin:

private final CountDownLatch waiter = new CountDownLatch(1);

ve testte gerektiği yerde:

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

Söylemesi gereksiz olabilir ama beklemeyi kısa tutmanız ve çok fazla yerde beklemeyi biriktirmemeniz gerektiğini unutmayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.