2015-01-21 4 views
11

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

कुछ परीक्षण हैं जो पूरे सूट को चलाने में असफल होते हैं, लेकिन स्वयं को पास करते हैं।

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

मेरा नेटवर्क कोड NSOperation ऑब्जेक्ट्स में encapsulated है जो NSOperationQueue पर चल रहे हैं। (मेरे आपरेशन कतार डिफ़ॉल्ट प्रकार है - मैं स्पष्ट रूप से अंतर्निहित GCD कतार सीरियल या समवर्ती होने के लिए सेट नहीं किया है।)

मैं इन परीक्षणों को ठीक करने में क्या देखने के लिए कर सकते हैं? this post on objc.io पढ़ने के बाद, मुझे लगता है कि वे किसी प्रकार की अलगाव समस्या से पीड़ित हैं।

उत्तर

8

आप सही रास्ते पर हैं। Objc.io आलेख द्वारा सुझाए गए समाधान शायद ऐसा करने का सही तरीका है लेकिन कुछ रिफैक्टरिंग की आवश्यकता है। यदि आप एक कोड परिवर्तन बिंग पर जाने से पहले परीक्षण को पहले चरण के रूप में बनाना चाहते हैं, तो यहां आप यह कैसे कर सकते हैं।

आम तौर पर आप अपने सभी एसिंक परीक्षण करने के लिए XCTestExpectations का उपयोग कर सकते हैं। एक मानक पैटर्न इस तरह जाना हो सकता है:

XCTestExpectation *doThingPromise = [self expetationWithDescription:@"Bazingo"]; 
[SomeService doThingOnSucceed:^{ 
    [doThingPromise fulfill]; 
} onFail:^ { 
}]; 
[self waitForExpectationsWithTimeout:1.0 handler:^(NSError *error) { 
    expect(error).to.beNil(); 
}] 

यह ठीक काम करता है अगर [SomeService doThingOnSucceed: onFail:] एक async अनुरोध को वापस ले आग और उसके बाद सीधे हल करता है। लेकिन क्या होगा अगर इस तरह की और विदेशी चीजों किया:

+ (void)doThingOnSucceed:onFail: { 
    [Thing do it]; 
    [self.context performBlock:^{ 
    // Uh oh Farfalle-Os 
    success(); 
    }]; 
} 

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

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

छोटी अवधि के स्पष्ट हैक चारों ओर चीजें खत्म होने तक आपके परीक्षण को रोकना है।

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 
[SomeService doThingOnComplete:^{ 
    dispatch_semaphore_signal(semaphore); 
}]; 
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; 
} 

यह स्पष्ट रूप से पूरा करने से एक परीक्षण से बचाता है जब तक सब कुछ खत्म, जिसका अर्थ है कोई अन्य परीक्षण जब तक इस परीक्षण खत्म चला सकते हैं: यहाँ एक उदाहरण है।

यदि आपके परीक्षण/कोड में इनमें से बहुत से मामले हैं, तो मैं एक प्रेषण समूह बनाने के objc.io समाधान की अनुशंसा करता हूं जिसे आप प्रत्येक परीक्षण के बाद प्रतीक्षा कर सकते हैं।

+0

(स्विफ्ट में) इस लागू करने के लिए कोशिश कर रहा है और मैं खोजने रहा है कि यह काम करता है, लेकिन यह सेमाफोर संकेतों के रूप में के रूप में जल्द जारी रखने के लिए नहीं है। यह Runloop.run पर लटकी हुई है जब तक समय समाप्त होता है। इस उम्मीद है? मेरे कोड: 'जबकि semaphore.wait (टाइमआउट: है अब()) == .timedOut { RunLoop.current.run (जब तक: तिथि (timeIntervalSinceNow: 10)) }' – guptron

1

NSOperationQueue से लड़ने के बाद और कुछ दिनों के लिए waitUntilAllOperationsAreFinished से एक गलत रूप से गलत वापसी मैंने एक सरल विकल्प पर मारा है: अपने परीक्षणों को एकाधिक परीक्षण लक्ष्यों में विभाजित करें। यह आपके परीक्षणों को अपना स्वयं का 'ऐप' वातावरण देता है और, इस मामले में अधिक महत्वपूर्ण बात यह सुनिश्चित करती है कि एक्सकोड/एक्ससीयूनीट उन्हें क्रमशः चलाएगा ताकि वे एक दूसरे के साथ हस्तक्षेप नहीं कर सकें - जब तक कि वे डेटाबेस को गंदे छोड़ने जैसी चीजें न करें (जो शायद होना चाहिए वैसे भी एक विफलता)।

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

Extra targets

आप देख सकते हैं कि परीक्षण परीक्षण लक्ष्य योजना का निरीक्षण द्वारा क्रियान्वित कर रहे। योजना में आप की आप लक्ष्यों का परीक्षण करने और उन्हें नीचे अपने व्यक्तिगत परीक्षण दोनों (सभी) देखना चाहिए।

Scheme editor

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