2012-09-17 18 views
13

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

मैं नियमित रूप से अपने ऐप में dispatch_async का उपयोग करता हूं, और मुझे समस्या परीक्षण करने में समस्या आ रही है। समस्या यह है कि मेरे परीक्षण के बाद ब्लॉक निष्पादित हो चुका है, क्योंकि यह मुख्य कतार पर असीमित रूप से चल रहा है। ब्लॉक को निष्पादित होने तक किसी भी तरह प्रतीक्षा करने का कोई तरीका है और फिर परीक्षण के साथ जारी रखें।

मैं ऐसा ही इकाई परीक्षण

- (viod)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // Test passes on this 
    [self.serviceClient fetchDataForUserId:self.userId]; 


    // Test fails on this because it's asynchronous 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self.serviceClient fetchDataForUserId:self.userId]; 
    }); 
} 

- (void)testShouldFetchUserDataUsingCorrectId 
{ 
    static NSString *userId = @"sdfsdfsdfsdf"; 
    self.viewController.userId = userId; 
    self.viewController.serviceClient = [[OCMockObject niceMockForClass:[ServiceClient class]]; 

    [[(OCMockObject *)self.viewController.serviceClient expect] fetchDataForUserId:userId]; 
    [self.viewController view]; 
    [(OCMockObject *)self.viewController.serviceClient verify]; 
} 

उत्तर

37

मुख्य लूप संक्षेप में चलाने के लिए यह async ब्लॉक कॉल करने के लिए:

- (void)testShouldFetchUserDataUsingCorrectId { 
    static NSString *userId = @"sdfsdfsdfsdf"; 
    self.viewController.userId = userId; 
    self.viewController.serviceClient = [[OCMockObject niceMockForClass:[ServiceClient class]]; 

    [[(OCMockObject *)self.viewController.serviceClient expect] fetchDataForUserId:userId]; 
    [self.viewController view]; 
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; 
    [(OCMockObject *)self.viewController.serviceClient verify]; 
} 

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

+0

इस कोड का उपयोग करके, ब्लॉक को बिलकुल नहीं बुलाया जा रहा है, परीक्षण के बाद भी नहीं। – aryaxt

+0

मैंने अपना जवाब संशोधित कर दिया है। मैंने इस दृष्टिकोण का अधिक अच्छी तरह से परीक्षण किया। –

+0

धन्यवाद। यह विधि विश्वसनीय नहीं लगती है, लेकिन मुझे एक बेहतर समाधान नहीं मिला है, इसलिए मैं आगे बढ़ूंगा और उम्मीद करूँगा कि यह मेरे परीक्षणों को तोड़ नहीं देगा। – aryaxt

10

लपेटें निष्पादन एक dispatch_group में की वजह से ब्लॉक करने के लिए एक पूरा होने से पारित और फिर क्रियान्वित सभी के माध्यम से ब्लॉक भेजा खत्म करने के लिए समूह के लिए प्रतीक्षा नहीं करना चाहते dispatch_group_wait()

+0

बहुत रोचक। पहले dispatch_group के बारे में कभी नहीं सुना। मैं फिर से NSOperationQueues का उपयोग नहीं कर सकता। जीसीडी के साथ मेरी एकमात्र समस्या इस कार्यक्षमता की कमी थी – aryaxt

+0

@ एरैक्सट यूप, प्रेषण समूह बहुत उपयोगी हैं, लेकिन शायद ही कभी कहीं भी उल्लेख किया गया है (यहां तक ​​कि आधिकारिक ऐप्पल दस्तावेज़ भी उनके बारे में बहुत verbose नहीं हैं) – JustSid

+0

यह बहुत उपयोगी तकनीक है। इसे और अधिक प्राप्त करना चाहिए। – e2l3n

0

एक समान विधि हस्ताक्षर के साथ dispatch_async रैपर बनाएं जो बदले में वास्तविक dispatch_async पर कॉल करता है। निर्भरता आपके उत्पादन वर्ग में रैपर इंजेक्ट करें और इसका उपयोग करें।

फिर एक नकली रैपर बनाएं, जो ब्लॉक को अवरुद्ध करता है और सभी संलग्न ब्लॉक को सिंक्रनाइज़ करने के लिए एक अतिरिक्त विधि है। हो सकता है कि ब्लॉक को निष्पादित किए जाने पर अधिक अवरोधक "अवरोध" करें।

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

dispatch_group एक अच्छे समाधान की तरह लगता है, लेकिन आपके उत्पादन वर्ग को ब्लॉक के अंत में प्रेषण समूह को पिंग करने के लिए "पता" करने की आवश्यकता होगी।