मैं 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
यदि आप सोनारक्बी जैसे कोड विश्लेषण टूल का उपयोग कर रहे हैं, तो वे Thread.sleepकुछ ऐसा कहने के बारे में शिकायत करेंगे जैसे किसी परीक्षण में थ्रेड का उपयोग करना आमतौर पर एक बुरा विचार है। यह भंगुर परीक्षण बनाता है जो पर्यावरण के आधार पर अप्रत्याशित रूप से विफल हो सकता है ("मेरी मशीन पर गुजरता है!") या लोड। समय पर निर्भर न करें (मोक्स का उपयोग करें) या अतुलनीय परीक्षण के लिए वातारण जैसे पुस्तकालयों का उपयोग करें।
FuryFart

4
इस उत्तर को हटा दिया जाना चाहिए, और हानिकारक माना जाना चाहिए। नीचे एक बेहतर उत्तर है stackoverflow.com/a/35163873/1229735
यति

73

Thread.sleep () ज्यादातर मामलों में काम कर सकता है, लेकिन आमतौर पर यदि आप प्रतीक्षा कर रहे हैं, तो आप वास्तव में किसी विशेष स्थिति या स्थिति के आने की प्रतीक्षा कर रहे हैं। Thread.sleep () इस बात की गारंटी नहीं देता है कि आप जो भी इंतजार कर रहे हैं वह वास्तव में हुआ है।

यदि आप उदाहरण के लिए आराम के अनुरोध पर प्रतीक्षा कर रहे हैं, तो यह आमतौर पर 5 सेकंड में वापस आ सकता है, लेकिन यदि आप अपनी नींद को 5 सेकंड के लिए निर्धारित करते हैं तो आपका अनुरोध 10 सेकंड में वापस आ जाता है, आपका परीक्षण विफल हो रहा है।

इस उपाय को मापने के लिए JayWay में एक महान उपयोगिता है, जिसे Awatility कहा जाता है, जो यह सुनिश्चित करने के लिए एकदम सही है कि आपके जाने से पहले एक विशिष्ट स्थिति उत्पन्न होती है।

यह एक अच्छा धाराप्रवाह एपीआई भी है

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

https://github.com/jayway/awaitility


मुझे एंड्रॉइड स्टूडियो में संकलन करने की प्रतीक्षा नहीं की जा सकती है।
इगोरगानापोलस्की

क्या आपने इस लाइन को आप फ़ाइल में जोड़ा है: 'org.awaitility: waitility: 3.0.0' संकलित करें?
समोह

नहीं। आप इसे एक परीक्षण के मामले में जोड़ देंगे जहां आप एक विशेष स्थिति के लिए इंतजार करना चाहते हैं
बेन ग्लासर

16

यदि आपका स्टेटिक कोड एनालाइज़र (सोनारक्यूब की तरह) शिकायत करता है, लेकिन आप नींद के बजाय किसी अन्य तरीके के बारे में नहीं सोच सकते हैं, तो आप हैक के साथ कोशिश कर सकते हैं जैसे: Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true); यह वैचारिक रूप से गलत है, लेकिन यह वैसा ही है Thread.sleep(1000)

सबसे अच्छा तरीका, निश्चित रूप से, एक कॉल करने योग्य है, जो आपकी उपयुक्त स्थिति के बजाय true, जो मेरे पास है।

https://github.com/awaitility/awaitility


@ जितेंद्र: ध्यान दें कि Awaitility में Durationकक्षा होती थी, लेकिन संस्करण 4 के बाद से उन्होंने इसका नाम बदल दिया Durations
जैकब वैन लिंगेन

एक कैविएट, यदि आप चाहते हैं कि मतदान में देरी 10 सेकंड या उससे अधिक हो, तो समय-सीमा को 10 सेकंड से अधिक बढ़ाना सुनिश्चित करें क्योंकि यह डिफ़ॉल्ट समयबाह्य है और प्रतीक्षाशीलता की शिकायत होगी कि मतदान में देरी से कम समय लगता है।
ध्यान केंद्रित करें

14

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

यह पुस्तकालय समय इकाई के लिए अधिक स्पष्ट व्याख्या प्रदान करता है। आप 'HOURS' / 'MINUTES' / 'SECONDS' का उपयोग कर सकते हैं।


अगर मैं एक परीक्षण के भीतर से एक श्रमिक धागा शुरू करता हूं, तो क्या sleep()कार्यकर्ता धागे को प्रभावित करेगा ?
एंथनी काँग


0

एक सामान्य समस्या है: समय का मजाक उड़ाना कठिन है। इसके अलावा, यूनिट परीक्षण में लंबे समय तक चलने / प्रतीक्षा कोड रखने के लिए वास्तव में बुरा अभ्यास है।

इसलिए, शेड्यूलिंग एपीआई को परीक्षण योग्य बनाने के लिए, मैंने इस तरह के एक वास्तविक और नकली कार्यान्वयन के साथ एक इंटरफ़ेस का उपयोग किया:

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

शायद कहने के लिए अनावश्यक है लेकिन यह ध्यान में रखते हुए कि आपको प्रतीक्षा समय छोटा रखना चाहिए और बहुत से स्थानों पर इंतजार नहीं करना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.