2010-10-28 12 views
6

बहु-थ्रेड वातावरण में JUnit का उपयोग करते समय मैं एक बुरी समस्या से मिलती हूं। निम्नलिखित कोड विफल होना चाहिए, लेकिन यह वास्तव में ग्रहण में गुजरता है।बहु-थ्रेड वातावरण में JUnit का उपयोग करके अजीब समस्या

public class ExampleTest extends TestCase { 

    private ExecutorService executor = Executors.newFixedThreadPool(10); 

    private volatile boolean isDone = false; 

    public void test() throws InterruptedException, ExecutionException { 
     executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        fail(); 
       } finally { 
        isDone = true; 
       } 
      } 
     }); 

     while (!isDone) { 
      Thread.sleep(1000); 
     } 
    } 
} 

और here'a एक और कोड, यहाँ मैं उपयोग Future.get() इस मामले में यह असफल हो जायेगी में, धागा बंद के लिए इंतजार करना।

public class ExampleTest extends TestCase { 

    private ExecutorService executor = Executors.newFixedThreadPool(10); 

    private volatile boolean isDone = false; 

    public void test() throws InterruptedException, ExecutionException { 
     Future future=executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        fail(); 
       } finally { 
        isDone = true; 
       } 
      } 
     }); 

     future.get(); 
    } 
} 

मैं इसे googled और पाया कि JUnit एकाधिक-धागा इकाई परीक्षण नहीं संभाल सकता है, लेकिन क्या कोड के इन दो टुकड़ों के बीच मतभेद है? धन्यवाद

उत्तर

6

जुनीट थ्रेड के अलावा धागे में होने वाले अपवादों को नहीं देख सकता है जिसमें परीक्षण चल रहे हैं। पहले मामले में, fail पर कॉल करके अपवाद के माध्यम से, यह executor द्वारा चलाए गए एक अलग थ्रेड में होता है। इसलिए यह जुनीट और परीक्षण पास के लिए दृश्यमान नहीं है।

दूसरे मामले में, executor द्वारा चलाए गए अलग थ्रेड में एक ही अपवाद होता है लेकिन जब आप future.get पर कॉल करते हैं तो अपवाद प्रभावी रूप से परीक्षण थ्रेड पर "वापस रिपोर्ट किया जाता है"। ऐसा इसलिए है क्योंकि future.get किसी भी अपवाद के कारण भविष्य की गणना विफल होने पर ExecutionException फेंकता है। जुनीट इस अपवाद को देखने में सक्षम है और इसलिए परीक्षण विफल रहता है।

+0

तो वहाँ किसी भी है इस मामले में जुनीट के लिए प्रतिस्थापन? – zjffdu

0

http://www.youtube.com/watch?v=wDN_EYUvUq0 (17:09 से शुरू) पर एक नज़र डालें, यह जुनीट और धागे के साथ आप समस्याओं को समझ सकते हैं।

मुझे लगता है कि आपके मामले में, get()ExecutionException फेंकता है और यही कारण है कि दूसरा परीक्षण विफल हो जाता है। पहले टेस्टकेस में, जुनीट अपवाद नहीं देखता है।

0

यह भी दिलचस्प तथ्य है कि ग्रहण और आईडीईए अपने जूनिट टेस्ट धावकों में वीएम उत्पन्न कर सकता है और उस पर कॉलिंग सिस्टम.एक्सिट() को समाप्त कर सकता है। इसका मतलब है कि यदि आप परीक्षण में ठीक से इंतजार नहीं करते हैं (जैसा कि आप ऊपर सोते हैं और उम्मीद है कि कार्य पूरा हो गया है), यह अप्रत्याशित रूप से बाहर निकल सकता है। दिलचस्प है, लेकिन बिल्कुल नहीं जो आप पूछ रहे थे!

विवरण के लिए इस link ...

1

के रूप में @ abhin4v बताया गया है, नए सूत्र में अपवाद निगल लिया हो जाता है। आप अपना खुद का fail -method प्रदान करने का प्रयास कर सकते हैं जो get() के साथ आपके उदाहरण में शीर्ष-स्तरीय थ्रेड के साथ सिंक्रनाइज़ करता है।

लेकिन फ़्यूचर्स का उपयोग करने की कोई आवश्यकता नहीं है, केवल विफलता को इंगित करने वाले साझा चर पर लिखें और newThreadId.join() का उपयोग करें। इसके अलावा, मुझे सादे जुनीट में इसे हल करने के किसी अन्य तरीके से अवगत नहीं है।

2

@zjffdu @ShiDoiSi के रूप में इंगित किया गया है, Thread.join() ठीक काम करता है यदि आपके पास एक एकल कार्यकर्ता धागा है जिसे आप ज़ोर देना चाहते हैं या विफल होना चाहते हैं।

आप एक से अधिक कार्यकर्ता धागे है, या यदि आप एक छोटे से अधिक सुविधा चाहते हैं, तो प्रदर्शन मल्टी-थ्रेडेड दावे के लिए एक JUnit विस्तार है: ConcurrentUnit:

public class ExampleTest extends ConcurrentTestCase { 
    private ExecutorService executor = Executors.newFixedThreadPool(10); 

    public void test() throws Throwable { 
     executor.submit(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        threadFail("Failure message"); 
       } finally { 
        resume(); 
       } 
      } 
     }); 

     threadWait(); 
    } 
} 

गुड लक

संबंधित मुद्दे