2010-03-10 13 views
11

मौलिक सवाल यह है कि मैं एक यूनिट टेस्ट कैसे बना सकता हूं जिसे किसी विधि को कॉल करने की आवश्यकता होती है, परीक्षण कक्षा पर होने वाली घटना के लिए प्रतीक्षा करें और फिर किसी अन्य विधि को कॉल करें (जिसे हम वास्तव में परीक्षण करना चाहते हैं)?टीडीडी असीमित घटनाओं को कैसे करें?

यहाँ परिदृश्य है अगर आप आगे पढ़ने के लिए समय:

मैं हार्डवेयर का एक टुकड़ा नियंत्रित करने के लिए है कि एक आवेदन के विकास कर रहा हूँ। हार्डवेयर उपलब्धता से निर्भरता से बचने के लिए, जब मैं अपना ऑब्जेक्ट बनाता हूं तो मैं निर्दिष्ट करता हूं कि हम परीक्षण मोड में चल रहे हैं। जब ऐसा होता है, तो जिस वर्ग का परीक्षण किया जा रहा है वह उपयुक्त ड्राइवर पदानुक्रम बनाता है (इस मामले में हार्डवेयर ड्राइवरों की पतली नकली परत)।

कल्पना कीजिए कि प्रश्न में वर्ग एक लिफ्ट है और मैं उस विधि का परीक्षण करना चाहता हूं जो मुझे लिफ्ट की मंजिल संख्या देता है। यहाँ कैसे मेरी काल्पनिक परीक्षण अभी की तरह लग रहा है:

[TestMethod] 
public void TestGetCurrentFloor() 
{ 
    var elevator = new Elevator(Elevator.Environment.Offline); 
    elevator.ElevatorArrivedOnFloor += TestElevatorArrived; 

    elevator.GoToFloor(5); 

    //Here's where I'm getting lost... I could block 
    //until TestElevatorArrived gives me a signal, but 
    //I'm not sure it's the best way 

    int floor = elevator.GetCurrentFloor(); 

    Assert.AreEqual(floor, 5); 
} 

संपादित करें:

सभी प्रश्नों के उत्तर के लिए धन्यवाद। इस प्रकार मैंने इसे कार्यान्वित करने का अंत किया:

[TestMethod] 
    public void TestGetCurrentFloor() 
    { 
     var elevator = new Elevator(Elevator.Environment.Offline); 
     elevator.ElevatorArrivedOnFloor += (s, e) => { Monitor.Pulse(this); }; 

     lock (this) 
     { 
      elevator.GoToFloor(5); 

      if (!Monitor.Wait(this, Timeout)) 
       Assert.Fail("Elevator did not reach destination in time"); 

      int floor = elevator.GetCurrentFloor(); 

      Assert.AreEqual(floor, 5); 
     } 
    } 
+0

क्या लक्ष्य ओएस पर कॉल अवरुद्ध होने जा रहे हैं? –

+0

नहीं। जैसे ही आप कॉल करते हैं .GoToFloor (मंजिल) यह लौटाता है, लेकिन लिफ्ट "स्थानांतरण" में स्थिति बदलती है, उस मंजिल तक पहुंचने में कुछ समय लगता है, और फिर यह एक घटना (जो एक अलग धागे में हो सकता है) उठाएगा –

+0

हाय, यह एक समस्या को हल करना चाहिए जिसमें मैंने एक असीमित ऑपरेशन का परीक्षण किया है। मैंने उपरोक्त कोड को शुरुआती बिंदु के रूप में उपयोग किया है, हालांकि मॉनिटर.पल्स लॉक को पुनः प्राप्त करने का इंतजार नहीं करता है और यह बार-बार आर्टर्ट का कारण बनता है। विफल ("ईवेंट नहीं आया") आग लगाना। कोई विचार यह क्यों हो सकता है ...! – Kildareflare

उत्तर

5

मुझे लगता है कि आप पहले से ही सही लाइनों पर हैं। परीक्षण तब तक इंतजार करने की ज़रूरत है जब तक कि घटना न हो या आप निर्णय लें कि इसे आने में बहुत लंबा समय लगेगा और इंतजार करना चाहिए।

ऐसा करने के लिए, आप मॉनिटर.एट का उपयोग अपने परीक्षण में एक टाइमआउट के साथ कर सकते हैं और इसे मॉनीटर के साथ संकेत दिया है। घटना आने पर पल्स।

 

[TestMethod] 
public void TestGetCurrentFloor() 
{ 
    var elevator = new Elevator(Elevator.Environment.Offline); 
    elevator.ElevatorArrivedOnFloor += TestElevatorArrived; 

    lock (this) 
    { 
     elevator.GoToFloor(5); // NOTE: this must hand off to a second thread, and the ElevatorArrivedOnFloor must be raised by this other thread otherwise the Monitor will be pulse before we've started waiting for it 

     if (!Monitor.Wait(this, TIMEOUT)) Assert.Fail("Event did not arrive in time."); 
    } 

    int floor = elevator.GetCurrentFloor(); 

    Assert.AreEqual(floor, 5); 
} 

private void TestElevatorArrived(int floor) 
{ 
    lock (this) 
    { 
     Monitor.Pulse(this); 
    } 
} 
 

(यहाँ Assert.Fail() कॉल जो कुछ तंत्र अपनी यूनिट परीक्षण उपकरण स्पष्ट रूप से एक परीक्षण नाकाम रहने के लिए का उपयोग करता है के साथ प्रतिस्थापित किया जाना चाहिए - या आप एक अपवाद फेंक सकता है।)

+0

इस तरह मैं कर रहा हूं, सिवाय इसके कि मैं इसे वेटहैंडल और घटना के लिए निर्दिष्ट विधि के बजाय लैम्ब्डा के साथ कर रहा हूं, लेकिन विचार बिल्कुल वही है। –

+0

हाय, यह एक समस्या को हल करना चाहिए जिसमें मैंने एक असीमित ऑपरेशन का परीक्षण किया है। मैंने उपरोक्त कोड को शुरुआती बिंदु के रूप में उपयोग किया है, हालांकि मॉनिटर.पल्स लॉक को पुनः प्राप्त करने का इंतजार नहीं करता है और यह बार-बार आर्टर्ट का कारण बनता है। विफल ("ईवेंट नहीं आया") आग लगाना। कोई विचार यह क्यों हो सकता है ...! – Kildareflare

+0

@ किल्डारेफ्लेयर: पल्स मॉनिटर.एट() को प्रतीक्षा करने का कारण बनता है। ध्यान दें कि जब Monitor.Wait() प्रतीक्षा समाप्त हो जाता है (नाड़ी की वजह से या क्योंकि यह समय समाप्त हो गया है) तो इसे लॉक को पुनः प्राप्त करना होगा, इसलिए यह हो सकता है कि Monitor.Wait() पहले ही समय हो चुका है लेकिन आप बाद में संदेश देखते हैं जब यह ताला वापस पाने में सक्षम है। मेरा अनुमान होगा कि आपने टाइमआउट को बहुत छोटा सेट किया होगा: यह मिलीसेकंड में है, क्या आप इसके बजाय सेकंड निर्दिष्ट कर रहे हैं? –

2

हो सकता है कि यह सिर्फ एक गरीब उदाहरण है, लेकिन आपकी लिफ्ट एक ऐसी चीज की तुलना में एक राज्य मशीन की तरह लगती है जो असीमित रूप से संसाधित हो रही है।

तो आपके पहले परीक्षणों का परीक्षण यह जांच सकता है कि GoToFloor() राज्य को आगे बढ़ने के लिए सेट करेगा और जिस दिशा में यह आगे बढ़ रहा है वह सही है।

फिर परीक्षण का अगला सेट TestElevatorArrived() पर होगा, और परीक्षण करेगा कि यदि आपका राज्य एक निश्चित मंजिल की तरफ बढ़ रहा था, तो वास्तविक आंदोलन (यानी, कार्य जिसे अतुल्यकालिक प्रतीक्षा के बाद बुलाया जाता है, या हैंडलर एक 'चालित' घटना फायरिंग हार्डवेयर के लिए) राज्य को अपेक्षित मंजिल पर सेट करेगा।

अन्यथा, आप जो परीक्षण कर रहे हैं, वह सबसे अधिक संभावना है कि हार्डवेयर का मजाक सही समय पर चल रहा है और चल रहा है, जो सही नहीं लगता है।

+1

आप सही हैं, मेरी लिफ्ट राज्य पैटर्न को लागू करती है और मैं पहले से ही ऐसे परीक्षण कर रहा हूं। अगर मैं इस विशिष्ट मामले में सबसे अच्छा काम करना चाहता हूं तो मैं उलझन में आया हूं। –

+1

आह, इस विशिष्ट मामले के लिए, मैं नहीं कहूंगा। कंबल नहीं कहना चाहता था क्योंकि ऐसा संभवतः (शायद?) टाइमर/टाइमआउट और व्हाट्सॉट के साथ परीक्षण के लिए कुछ अच्छे मामले हैं। लेकिन यहां, आप "प्रतीक्षा" पर क्या कर रहे हैं, यह कुछ हार्डवेयर करने के लिए आपका हार्डवेयर होगा, जो आप यूनिट परीक्षण की कोशिश नहीं कर रहे हैं। – Tanzelax

2

यह मेरा समान दृष्टिकोण है।

[TestMethod] 
    public void TestGetCurrentFloor() 
    { 
     var completedSync = new ManualResetEvent(false); 
     var elevator = new Elevator(Elevator.Environment.Offline); 

     elevator.ElevatorArrivedOnFloor += delegate(object sender, EventArgs e) 
     { 
      completedSync.Set(); 
     }; 

     elevator.GoToFloor(5); 

     completedSync.WaitOne(SOME_TIMEOUT_VALUE); 

     int floor = elevator.GetCurrentFloor(); 

     Assert.AreEqual(floor, 5); 
    } 

आप अपने ईवेंट हैंडलर को कॉल करने के लिए प्रतीक्षा करने के लिए WaitOne() कॉल के वापसी मूल्य का भी परीक्षण कर सकते हैं।

0

मुझे वास्तव में मॉनिटर के साथ रेस-हालत पसंद नहीं है। ऊपर/पल्स/प्रतीक्षा विधि।

[TestMethod] 
public void TestGetCurrentFloor() 
{ 
    // NUnit has something very similar to this, I'm going from memory 
    this.TestCounter.reset(); 

    var elevator = new Elevator(Elevator.Environment.Offline); 
    elevator.ElevatorArrivedOnFloor += (s,e) => { Assert.That(e.floor).Is(5) } 

    elevator.GoToFloor(5); 

    // It should complete within 5 seconds.. 
    Thread.Sleep(1000 * 5); 
    Assert.That(elevator.GetCurrentFloor()).Is(5); 

    Assert.That(this.TestCounter.Count).Is(2); 
} 

मैं क्योंकि लिफ्ट 500ms के भीतर आता है, तो आप एक और 4500ms इंतजार कर छोड़ दिया रहे हैं इस समाधान पसंद नहीं है:

एक नहीं-तो-अच्छा, लेकिन प्रभावी तरीका निम्नलिखित की तरह कुछ होगा। यदि आपके पास इस तरह के कई परीक्षण थे, और आप चाहते थे कि आपके परीक्षण जल्दी हो जाएं, मैं पूरी तरह से इस परिदृश्य से बचूंगा। हालांकि, इस प्रकार का परीक्षण प्रदर्शन/स्वच्छता जांच के रूप में भी दोगुना हो जाता है।

यह सुनिश्चित करना चाहते हैं कि लिफ्ट 2 सेकंड के भीतर आती है? टाइमआउट बदलें।

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