गो

2015-05-24 3 views
7

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

लेकिन, मेरा unittests नींद का उपयोग कर रहे इन async कार्यों के लिए प्रतीक्षा करने के लिए पूरा करने के लिए:

// Send notification event. 
mock.devices <- []sparkapi.Device{deviceA, deviceFuncs, deviceRefresh} 

// Wait for go-routine to process event. 
time.Sleep(time.Microsecond) 

// Check that no refresh method was called. 
c.Check(mock.actionArgs, check.DeepEquals, mockFunctionCall{}) 

टूट लगता है कि, लेकिन मैं एक बेहतर समाधान है कि नहीं जोड़ता है साथ आने के लिए नहीं कर पाए हैं गैर-परीक्षण उपयोग के लिए अनुचित ओवरहेड। क्या कोई उचित समाधान है जिसे मैंने याद किया है?

उत्तर

4

Soheil Hassas:

done := make(chan bool) 

// Send notification event. 
mock.devices <- Job { 
    Data: []sparkapi.Device{deviceA, deviceFuncs, deviceRefresh}, 
    Done: done, 
} 

// Wait until `done` is closed. 
<-done 

// Check that no refresh method was called. 
c.Check(mock.actionArgs, check.DeepEquals, mockFunctionCall{}) 

इस पद्धति का प्रयोग करके आप अपने परीक्षण के लिए एक टाइमआउट लागू कर सकते हैं Yeganeh का समाधान आमतौर पर जाने के लिए एक अच्छा तरीका है, या कम से कम कुछ ऐसा है। लेकिन यह एपीआई में एक बदलाव है, और यह कॉलर के लिए कुछ ओवरहेड बना सकता है (हालांकि ज्यादा नहीं; कॉलर को Done चैनल पास करने के लिए कॉलर की आवश्यकता नहीं है)। उस ने कहा, ऐसे मामले हैं जहां आप उस तरह की एसीके प्रणाली नहीं चाहते हैं।

मैं इस तरह की समस्या के लिए परीक्षण पैकेज Gomega की अत्यधिक अनुशंसा करता हूं। यह Ginkgo के साथ काम करने के लिए डिज़ाइन किया गया है, लेकिन इसका उपयोग स्टैंडअलोन किया जा सकता है। इसमें Consistently और Eventually मैचर्स के माध्यम से उत्कृष्ट एसिंक समर्थन शामिल है।

यह कहा गया है, जबकि गोमेगा गैर-बीडीडी परीक्षण प्रणाली के साथ अच्छी तरह से काम करता है (और testing में ठीक से एकीकृत करता है), यह एक बहुत बड़ी बात है और यह प्रतिबद्धता हो सकती है। यदि आप बस एक टुकड़ा चाहते हैं, तो आप इन दावों का अपना संस्करण लिख सकते हैं। मैं गोमेगा के दृष्टिकोण के बाद निम्नलिखित अनुशंसा करता हूं, जो केवल एक नींद की बजाय मतदान कर रहा है (यह अभी भी सोता है; इसे आपके एपीआई को फिर से डिजाइन किए बिना ठीक करना संभव नहीं है)।

यहां परीक्षण के लिए चीजों को देखने का तरीका बताया गया है।

http://play.golang.org/p/qpdEOsWYh0

const iterations = 10 
const interval = time.Millisecond 

func Consistently(f func()) { 
    for i := 0; i < iterations; i++ { 
     f() // Assuming here that `f()` panics on failure 
     time.Sleep(interval) 
    } 
} 

mock.devices <- []sparkapi.Device{deviceA, deviceFuncs, deviceRefresh} 
Consistently(c.Check(mock.actionArgs, check.DeepEquals, mockFunctionCall{})) 

जाहिर है आप पुनरावृत्तियों और अंतराल अपनी आवश्यकताओं से मिलान करने के लिए परिवर्तित कर सकते हैं: आप की तरह एक सहायक समारोह पैदा करते हैं। (गोमेगा एक 10 सेकंड टाइमआउट का उपयोग करता है, प्रत्येक 10 एमएमएस मतदान करता है।)

Consistently के किसी भी कार्यान्वयन का नकारात्मक हिस्सा यह है कि जो भी आपका टाइमआउट है, आपको हर टेस्ट रन खाना पड़ेगा। लेकिन इसके आसपास वास्तव में कोई रास्ता नहीं है। आपको यह तय करना होगा कि "ऐसा नहीं होने के लिए कितना समय लंबा है।" जब संभव हो, Eventually की जांच के लिए अपने परीक्षण को चालू करना अच्छा होता है, क्योंकि यह तेजी से सफल हो सकता है।

Eventually थोड़ा अधिक जटिल है, क्योंकि आपको पैनिक्स को सफल होने तक recover का उपयोग करने की आवश्यकता होगी, लेकिन यह बहुत बुरा नहीं है।कुछ इस तरह:

func Eventually(f func()) { 
    for i := 0; i < iterations; i++ { 
     if !panics(f) { 
      return 
     } 
     time.Sleep(interval) 
    } 
    panic("FAILED") 
} 

func panics(f func()) (success bool) { 
    defer func() { 
     if e := recover(); e != nil { 
      success = true 
     } 
    }() 
    f() 
    return 
} 

अंत में, यह सिर्फ तुम्हारे पास क्या है के लिए थोड़ी ज्यादा जटिल संस्करण है, लेकिन यह एक समारोह में तर्क लपेटता इसलिए यह थोड़ा बेहतर पढ़ता।

6

बेवकूफ तरीका done चैनल को अपने डेटा के साथ कार्यकर्ता go-routine को पास करना है। गो-दिनचर्या done चैनल close चाहिए और जब तक चैनल बंद कर दिया है अपने कोड इंतजार करना चाहिए:

// Wait until `done` is closed. 
select { 
case <-done: 
case <-time.After(10 * time.Second): 
    panic("timeout") 
} 
+0

मैं सवाल को सरल रखने की कोशिश कर रहा था, लेकिन शायद मैंने इसे खत्म कर दिया .. मैं एक घटक को डेटा भेज रहा हूं जो अन्य घटकों को पास कर सकता है, जो अन्य घटकों को पारित कर सकता है। पास ऑफ चेन में शाखाएं और कांटे और सभी प्रकार की जटिलता शामिल हो सकती है। इससे यह (अन्यथा उत्कृष्ट) सुझाव इतना उपयोगी नहीं होता है। – DonGar

+0

हाँ, यह बात है। श्रृंखला में आपके सभी घटकों को अपने एआईएनएनसी नौकरी के हिस्से के रूप में 'किया गया' चैनल प्राप्त करना चाहिए। अन्यथा, आप सीपीयू को बर्बाद कर देंगे और आपके जाने-माने जाने के लिए जागना और मतदान करना होगा। –

+0

@ डोंगर आप 'शुद्ध/संदर्भ' और http://blog.golang.org/pipelines में रुचि भी ले सकते हैं। जटिल क्रॉस-घटक श्रृंखलाओं के लिए कुछ बहुत अच्छे मौजूदा गो पैटर्न हैं। (टेस्टेबिलिटी सवाल नहीं बदलता है, लेकिन आपके समवर्ती डिजाइन को प्रभावित कर सकता है।) –