2010-02-25 15 views
7

मुझे एक समस्या का परीक्षण करने वाली इकाई इकाई है जो थ्रेड शुरू होने और समाप्त होने पर ईवेंट को सक्रिय करता है। हमलावर स्रोत का एक संस्करण में कटौती इस प्रकार है:इकाई एक थ्रेड से एक घटना फायरिंग का परीक्षण

public class ThreadRunner 
{ 
    private bool keepRunning; 

    public event EventHandler Started; 
    public event EventHandler Finished; 

    public void StartThreadTest() 
    { 
     this.keepRunning = true; 
     var thread = new Thread(new ThreadStart(this.LongRunningMethod)); 
     thread.Start(); 
    } 

    public void FinishThreadTest() 
    { 
     this.keepRunning = false; 
    } 

    protected void OnStarted() 
    { 
     if (this.Started != null) 
      this.Started(this, new EventArgs()); 
    } 

    protected void OnFinished() 
    { 
     if (this.Finished != null) 
      this.Finished(this, new EventArgs()); 
    } 

    private void LongRunningMethod() 
    { 
     this.OnStarted(); 

     while (this.keepRunning) 
      Thread.Sleep(100); 

     this.OnFinished(); 
    } 
} 

मैं तो जाँच करने के लिए है कि LongRunningMethod के बाद Finished घटना आग समाप्त हो गया है इस प्रकार एक परीक्षण है:

[TestClass] 
public class ThreadRunnerTests 
{ 
    [TestMethod] 
    public void CheckFinishedEventFiresTest() 
    { 
     var threadTest = new ThreadRunner(); 

     bool finished = false; 

     object locker = new object(); 

     threadTest.Finished += delegate(object sender, EventArgs e) 
     { 
      lock (locker) 
      { 
       finished = true; 
       Monitor.Pulse(locker); 
      } 
     }; 

     threadTest.StartThreadTest(); 
     threadTest.FinishThreadTest(); 

     lock (locker) 
     { 
      Monitor.Wait(locker, 1000); 
      Assert.IsTrue(finished); 
     } 
    } 
} 

तो यहाँ विचार यह है कि परीक्षण अधिकतम एक सेकंड के लिए अवरुद्ध होगा - या Finish ईवेंट निकाल दिया गया है - यह जांचने से पहले कि finished ध्वज सेट है या नहीं।

स्पष्ट रूप से मैंने कुछ गलत किया है क्योंकि कभी-कभी परीक्षण पास होगा, कभी-कभी यह नहीं होगा। डिबगिंग बहुत कठिन लगता है साथ ही ब्रेकपॉइंट्स जिन्हें मैं हिट करने की उम्मीद करता हूं (उदाहरण के लिए OnFinished विधि) हमेशा ऐसा नहीं लगता है।

मुझे लगता है कि यह थ्रेडिंग कार्यों के तरीके की मेरी गलतफहमी है, इसलिए उम्मीद है कि कोई मुझे प्रबुद्ध कर सकता है।

+0

सभी उत्तर के लिए धन्यवाद। मैंने धागा कार्यकर्ता विधि (यानी LongRunningMethod) होने पर एक और बग भी पेश किया, जब यह शुरू होता है तो इसे अपने नियंत्रण ध्वज सेट करें। आज निश्चित रूप से आपके कोड में दौड़ की स्थिति को पेश करने के तरीके में एक क्रैश कोर्स रहा है, दोह! – Dougc

उत्तर

15

एक लॉक यहाँ सिर्फ उचित नहीं है, तो आप एक घटना का संकेत करना चाहते हैं। उदाहरण के लिए:

public void CheckFinishedEventFiresTest() { 
     var threadTest = new ThreadRunner(); 
     var finished = new ManualResetEvent(false); 
     threadTest.Finished += delegate(object sender, EventArgs e) { 
      finished.Set(); 
     }; 
     threadTest.StartThreadTest(); 
     threadTest.FinishThreadTest(); 
     Assert.IsTrue(finished.WaitOne(1000)); 
    } 
2

आप परीक्षण गलत लगते हैं। मान लें कि threadTest.FinishThreadTest(); लॉक CheckFinishedEventFiresTest() में कोड द्वारा प्राप्त किया जाता है। फिर परीक्षण असफल होने जा रहा है। आपको यहां एक स्पष्ट दौड़ की स्थिति मिली है।

ध्यान दें कि FinishThreadTest() से वापस नहीं गारंटी कि धागा समाप्त हो गया है नहीं करता है। यह थ्रेड के लिए ध्वज सेट करता है, जिसे किसी भी पल पर विचार किया जा सकता है (मूल रूप से गारंटी नहीं देता है कि थ्रेड शेड्यूलर द्वारा तुरंत चलाया जाता है)।

आपके मामले में, थ्रेड सबसे अधिक व्यस्त Sleep() ing व्यस्त होगा। threadTest.FinishThreadTest(); पर कॉल करने के बाद लॉक सबसे अधिक संभवतः थ्रेड द्वारा अधिग्रहित किया जाएगा जहां CheckFinishedEventFiresTest() निष्पादित किया गया है। मॉनिटर 1 सेकंड इंतजार करेगा और फिर छोड़ देगा। उस लॉक के बाद जारी किया जाएगा, इसलिए प्रतिनिधि केवल उस पल को लॉक करने में सक्षम होगा।

+0

आह, निश्चित रूप से अब समझ में आता है। धन्यवाद व्लाद। – Dougc

4

Vlad बिल्कुल सही है, लेकिन मैं इस समस्या को स्पष्ट करने में एक और शॉट ले लेंगे:

// This runs on the other thread 
threadTest.Finished += delegate(object sender, EventArgs e) { 
    // I can't get this lock if the test thread gets here first! 
    lock (locker) { 
     finished = true; 
     Monitor.Pulse(locker); 
    } 
}; 

आप किसी तरह के इंतजार संभाल के साथ ऐसा कर सकते हैं। मैं का उपयोग एक ManualResetEvent चाहते हैं:

ManualResetEvent waitHandle = new ManualResetEvent(false); 
threadTest.Finished += delegate(object sender, EventArgs e) { 
    finished = true; 
    waitHandle.Set(); 
}; 

threadTest.StartThreadTest(); 
threadTest.FinishThreadTest(); 

// Specify a timeout so your test isn't hostage forever 
if (waitHandle.WaitOne(timeout, true)) { 
    Assert.IsTrue(finished); 
} 
+0

धन्यवाद जेफ। अभी भी एक अजीब मुद्दा प्रतीत होता है जहां थ्रेड कभी-कभी चलने के बाद बाहर नहीं निकलता है। फिनिश थ्रेडटेस्ट विधि द्वारा चलने वाले झंडे को स्विच किया गया है? यहां तक ​​कि अगर मैं एक बहुत ही उच्च मूल्य के लिए टाइमआउट ऊपर। – Dougc

+0

'LongRunningMethod' बाहर नहीं निकलता है? शायद दूसरे WaitOne पैरामीटर (बाहर निकलने के संदर्भ) के साथ कुछ मजाकिया व्यवसाय है। मैं nobugz 'नमूना कोशिश करेंगे, जिसका उद्देश्य एक ही चीज़ को पूरा करना है, लेकिन वैसे भी बेहतर है (अनावश्यक बूल के साथ वितरण)। –

+0

कोई बात नहीं, मैं बेवकूफ था (मूल प्रश्न पर मेरी टिप्पणी देखें)। धन्यवाद! – Dougc

3

मैं हाल ही में वस्तुओं है कि सिंक्रोनस और एसिंक्रोनस दोनों घटनाओं को प्रकाशित करने के लिए इकाई परीक्षण घटना दृश्यों पर ब्लॉग पोस्ट की एक श्रृंखला लिखा था। पद एक इकाई परीक्षण दृष्टिकोण और ढांचे का वर्णन करते हैं, और परीक्षण के साथ पूर्ण स्रोत कोड प्रदान करते हैं।

ढांचे परीक्षण का उपयोग करना तो जैसे लिखा जा सकता है:

AsyncEventPublisher publisher = new AsyncEventPublisher(); 

Action test =() => 
{ 
    publisher.RaiseA(); 
    publisher.RaiseB(); 
    publisher.RaiseC(); 
}; 

var expectedSequence = new[] { "EventA", "EventB", "EventC" }; 

EventMonitor.Assert(test, publisher, expectedSequence, TimeoutMS); 

EventMonitor सभी बड़े कार्य करता है और परीक्षण (कार्रवाई) चलाने के लिए और दावा है कि घटनाओं की उम्मीद अनुक्रम (expectedSequence) में उठाए गए हैं जाएगा। यह एसिंक्रोनस घटनाओं को संभालता है, और परीक्षण विफलता पर अच्छे नैदानिक ​​संदेशों को प्रिंट करता है।

वहाँ पदों मुद्दों और दृष्टिकोण, और स्रोत कोड का वर्णन भी में विस्तार का एक बहुत कुछ है:

http://gojisoft.com/blog/2010/04/22/event-sequence-unit-testing-part-1/

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