2009-11-20 9 views
5

का परीक्षण कैसे करें मैं बहु-थ्रेडेड सामानों का परीक्षण करने के तरीके में अपने पैर की उंगलियों को डुबो रहा हूं, लेकिन यह सुनिश्चित नहीं है कि कैसे शुरू किया जाए। मुझे यकीन है कि मैं और अधिक सामान बाहर निकालने होगा आसान अगर मैं सिर्फ सामान जा रहा हो सकता है हूँ, इसलिए अगर कोई मदद कर सकता है मुझे इस साधारण क्लास के लिए एक NUnit परीक्षण का मामला बारे में मैं सोच रहा था:सी #: मूल थ्रेडेड वर्कर क्लास

class Worker 
{ 
    public event EventHandler<EventArgs> Done = (s, e) => { }; 

    public void StartWork() 
    { 
     var thread = new Thread(Work) { Name = "Worker Thread" }; 
     thread.Start(); 
    } 

    private void Work() 
    { 
     // Do some heavy lifting 
     Thread.Sleep(500); 
     Done(this, EventArgs.Empty); 
    } 
} 

मैं चाहते हैं क्या परीक्षण बस है: Done ईवेंट समाप्त होने पर उठाया गया है। अगर यह तुल्यकालिक था, तो मुझे कोई समस्या नहीं होगी, लेकिन यह सुनिश्चित नहीं है कि यह कहां से शुरू हो सकता है। एक साधारण परीक्षण मल्टी-थ्रेडेड अगर यह नहीं था (और Work विधि निजी नहीं था) हो सकता है:

[TestFixture] 
class WorkerTests 
{ 
    [Test] 
    public void DoWork_WhenDone_EventIsRaised() 
    { 
     var worker = new Worker(); 

     var eventWasRaised = false; 
     worker.Done += (s, e) => eventWasRaised = true; 

     worker.Work(); 
     Assert.That(eventWasRaised); 
    } 
} 

किसी भी संकेत दिए गए?

उत्तर

7

आपको मैन्युअल रीसेट इवेंट का उपयोग करने की आवश्यकता है - अधिक जानकारी के लिए Unit Testing Multi-Threaded Asynchronous Events देखें।

कुछ की तरह:

[Test] 
public void DoWork_WhenDone_EventIsRaised() 
{ 
    var worker = new Worker(); 

    var eventWasRaised = false; 
    var mre = new ManualResetEvent(false); 
    worker.Done += (s, e) => { eventWasRaised= true; mre.Set(); }; 

    worker.Work(); 
    mre.WaitOne(1000); 
    Assert.That(eventWasRaised); 
} 
+2

eventRaisedFlag छोड़ा जा सकता है। ध्वज के रूप में घटना का उपयोग करना आसान है। Assert.That (mre.WaitOne (1000)); –

+0

ओह, अब यह चालाक है ... शानदार! @ वाडमीस्ट: अगर वेटऑन को कॉल करने से पहले ईवेंट समाप्त हो जाए तो यह कैसे काम करेगा? – Svish

+0

ओह, मुझे लगता है कि आप AutoResetEvent के बजाय मैन्युअल रीसेट इवेंट का उपयोग क्यों करेंगे? – Svish

1

मुख्य समस्या यह है कि आप परीक्षण पिरोया एप्लिकेशन के साथ लगता है वास्तव में परीक्षण डाटा के साथ धागा उत्तेजक क्योंकि आप मुख्य थ्रेड पर ब्लॉक करने के लिए अन्य धागा बाहर निकलता तक इंतजार करने की आवश्यकता होगी है।

जिस तरह से हमने इसके साथ काम किया है, वह सुझाव देता है कि आप इसे सिंक्रनाइज़ करते हैं। यह आपको तार्किक व्यवहार का परीक्षण करने की अनुमति देता है लेकिन यह निश्चित रूप से डेडलॉक्स और दौड़ की स्थितियों का पता नहीं लगाएगा (यह नहीं कि परीक्षण इन चीजों को आसानी से जोर दे सकता है)।

1

आप एक सामान्य पैटर्न का उपयोग कर सकते हैं जो थ्रेड निर्माण को बाहरी वर्ग में उजागर करता है।

class Worker 
{ 
    public event EventHandler<EventArgs> Done = (s, e) => { }; 

    public void StartWork() 
    { 
     var thread = CreateThread(); 
     thread.Start(); 
    } 

    // Seam for extension and testability 
    virtual protected Thread CreateThread() 
    { 
     return new Thread(Work) { Name = "Worker Thread" }; 
    } 

    private void Work() 
    { 
     // Do some heavy lifting 
     Thread.Sleep(500); 
     Done(this, EventArgs.Empty); 
    } 
} 

उप-वर्ग को परिभाषित करें कि धागा को उजागर करता है:

class WorkerForTest : Worker 
{ 
    internal Thread thread; 

    protected override Thread CreateThread() 
    { 
     thread = base.CreateThread(); 
     return thread; 
    } 
} 

धागे से परीक्षण सिंक्रनाइज़:

[TestFixture] 
class WorkerTests 
{ 
    [Test] 
    public void DoWork_WhenDone_EventIsRaised() 
    { 
     var worker = new WorkerForTest(); 

     var eventWasRaised = false; 
     worker.Done += (s, e) => eventWasRaised = true; 

     worker.StartWork(); 

     // Use the seam for synchronizing the thread in the test 
     worker.thread.Join(); 
     Assert.That(eventWasRaised); 
    } 
} 

कक्षा में आभासी विधि के लिए धागा निर्माण निकालने

टेस्टेबिलिटी के लिए डिज़ाइन के इस मामले में पट्टिन द्वारा परीक्षण थ्रेड सिंक्रनाइज़ करने के फायदे हैं जी उसे जोर से पहले सोने के लिए:

  • यह झूठी नकारात्मक विफलताओं की तरह जब परीक्षण धागा अवधि कि आमतौर पर पर्याप्त कार्यकर्ता धागा समाप्त करने के लिए के लिए है के लिए सोने के लिए डाल हो सकता है नहीं होगा।
  • यह धीमा नहीं होगा क्योंकि नींद का समय सुनिश्चित करने के लिए बफर लेता है। यह महत्वपूर्ण है जब सूट में कई परीक्षण इस पर निर्भर करते हैं।
1

यहाँ दो विकल्प हो सकता है: 1) कर्मी को प्रतीक्षा विधि जोड़ें ताकि आप पूरा होने 2 इंतजार कर सकते हैं) सरल बूलियन उपयोग घटना वस्तु के बजाय (AutoResetEvent)

आम तौर पर, हर इंतजार निर्दिष्ट टाइमआउट के लिए इंतजार करना है। नीचे दिए गए नमूनों में प्रतीक्षा अनंत है।

पहले विकल्प:

class Worker 
{ 
//... 
    Thread thread; 

    public void StartWork() 
    { 
     thread = new Thread(Work) { Name = "Worker Thread" }; 
     thread.Start(); 
    } 

    void WaitCompletion() 
    { 
    if (thread != null) thread.Join(); 
    } 
//... 
} 

[TestFixture] 
class WorkerTests 
{ 
    [Test] 
    public void DoWork_WhenDone_EventIsRaised() 
    { 
     var worker = new Worker(); 

     var eventWasRaised = false; 
     worker.Done += (s, e) => eventWasRaised = true; 

     worker.Work(); 
     worker.WaitCompletion(); 

     Assert.That(eventWasRaised); 
    } 
} 

दूसरा विकल्प: (प्रतीक्षा टाइमआउट साथ किया जा सकता)

[TestFixture] 
class WorkerTests 
{ 
    [Test] 
    public void DoWork_WhenDone_EventIsRaised() 
    { 
     var worker = new Worker(); 

     AutoResetEvent eventWasRaised = new AutoResetEvent(false); 
     worker.Done += (s, e) => eventWasRaised.Set(); 

     worker.Work(); 
     Assert.That(eventWasRaised.WaitOne()); 
    } 
} 
संबंधित मुद्दे