2009-06-09 10 views
12

एक खेल के लिए मैं विकसित कर रहा हूं, मेरे पास कई मॉडल वर्ग हैं जो उनके राज्य में बदलाव करते समय अधिसूचनाएं ट्रिगर करते हैं। फिर, दृश्य उन अधिसूचनाओं की सदस्यता लेता है और उन पर प्रतिक्रिया कर सकता है।OCUnit परीक्षण NSNotification वितरण

मैं ओसीयूनीट के साथ मॉडल के लिए अपने यूनिट परीक्षण कर रहा हूं, और यह कहना चाहता हूं कि अपेक्षित नोटिफिकेशन पोस्ट किए गए थे। कि के लिए, मैं कुछ इस तरह कर रहा हूँ:

- (void)testSomething { 
    [[NSNotificationCenter defaultCenter] addObserver:notifications selector:@selector(addObject:) name:kNotificationMoved object:board]; 

    Board *board = [[Board alloc] init]; 
    Tile *tile = [Tile newTile]; 

    [board addTile:tile]; 

    [board move:tile]; 

    STAssertEquals((NSUInteger)1, [notifications count], nil); 
    // Assert the contents of the userInfo as well here 

    [board release]; 
} 

विचार है कि NSNotificationCenter अपने addObject: विधि को फोन करके NSMutableArray को सूचनाएं जोड़ देगा है।

जब मैं इसे चलाता हूं, हालांकि, मुझे लगता है कि addObject: किसी अन्य ऑब्जेक्ट (मेरे NSMutableArray पर) को भेजा जा रहा है जिससे ओसीयूनीट काम करना बंद कर देता है। हालांकि, अगर मैं कुछ कोड (जैसे release कॉल, या एक नया यूनिट परीक्षण जोड़ता हूं) टिप्पणी करता हूं तो सब कुछ अपेक्षित काम करना शुरू कर देता है।

मुझे लगता है कि इसे एक समय के मुद्दे के साथ, या NSNotificationCenter किसी भी तरह से रन लूप पर निर्भर होना है।

क्या इसका परीक्षण करने की कोई सिफारिश है? मुझे पता है कि मैं Board में एक सेटर जोड़ सकता हूं और अपना खुद का NSNotificationCenter इंजेक्ट कर सकता हूं, लेकिन मैं इसे करने का एक तेज़ तरीका ढूंढ रहा हूं (शायद NSNotificationCenter गतिशील रूप से प्रतिस्थापित करने के तरीके पर कुछ चाल)।

+3

+1 यूनिट परीक्षण अधिसूचनाओं के चालाक तरीके से +1! –

उत्तर

5

समस्या मिली। सूचनाओं का परीक्षण करते समय आपको पर्यवेक्षक को परीक्षण करने के बाद इसे हटाने की आवश्यकता होती है। कार्य कोड:

- (void)testSomething { 
    [[NSNotificationCenter defaultCenter] addObserver:notifications selector:@selector(addObject:) name:kNotificationMoved object:board]; 

    Board *board = [[Board alloc] init]; 
    Tile *tile = [Tile newTile]; 

    [board addTile:tile]; 

    [board move:tile]; 

    STAssertEquals((NSUInteger)1, [notifications count], nil); 
    // Assert the contents of the userInfo as well here 

    [board release]; 
    [[NSNotificationCenter defaultCenter] removeObserver:notifications name:kNotificationMoved object:board]; 
} 

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

0

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

मुझे लगता है कि आपके द्वारा पोस्ट किए गए स्निपेट में सबकुछ सही है। हो सकता है कि म्यूटेबल सरणी 'नोटिफिकेशन' के साथ कोई समस्या हो। क्या आपने इसे सही तरीके से रखा और बनाए रखा? अधिसूचना चाल का उपयोग करने के बजाय मैन्युअल रूप से कुछ ऑब्जेक्ट जोड़ने का प्रयास करें।

+0

मैं सरणी को [NSMutableArray arrayWithCapacity] के साथ आवंटित कर रहा हूं। मैं इसे बरकरार नहीं रख रहा हूं (यह एक स्थानीय चर है, इसलिए NSAutoReleasePool इसे अभी तक जारी नहीं करेगा)। – pgb

+0

मेरी समस्या मिली। मैं NSNotificationCenter से पर्यवेक्षक को नहीं हटा रहा हूं, इसलिए जब कोई दूसरा परीक्षण चलता है तो यह किसी ऑब्जेक्ट को सूचित करने का प्रयास करता है जो ढेर में मौजूद नहीं है। – pgb

0

यदि आपको संदेह है कि आपके परीक्षणों में समय के मुद्दे हैं - तो आप अपने बोर्ड ऑब्जेक्ट में अपनी खुद की अधिसूचना तंत्र इंजेक्शन पर विचार करना चाहेंगे (जो शायद मौजूदा सेब संस्करण का एक आवरण है)।

यही कारण है:

Board *board = [[Board alloc] initWithNotifier: someOtherNotifierConformingToAProtocol]; 

मुमकिन है अपने बोर्ड वस्तु पदों कुछ अधिसूचना - आप का प्रयोग करेंगे आपके कि कोड में सूचक इंजेक्शन:

-(void) someBoardMethod { 

    // .... 

    // Send your notification indirectly through your object 
    [myNotifier pushUpdateNotification: myAttribute]; 
} 

अपने परीक्षण में - अब आप अविवेक का एक स्तर है कि आप परीक्षण के लिए उपयोग कर सकते हैं, ताकि आप अपने एपोटोकॉल के अनुरूप एक टेस्ट क्लास को कार्यान्वित कर सकें - और शायद pushUpdateNotification: कॉल की गणना कर सकता है। आपके वास्तविक कोड में आप उस कोड को समाहित करते हैं जो आपके पास पहले से बोर्ड में है जो अधिसूचना करता है।

निश्चित रूप से यह जहां MockObjects उपयोगी होते हैं का एक उत्कृष्ट उदाहरण है - और OCMock जो अच्छी तरह से आप एक परीक्षण वर्ग गिनती करना है बिना ऐसा करते हैं नहीं है (देखें: http://www.mulle-kybernetik.com/software/OCMock/)

अपने परीक्षण होगा संभावित रूप से एक लाइन कुछ है:

[[myMockNotifer expect] pushUpdateNotification: someAttribute]; 

वैकल्पिक रूप से आप अधिसूचनाओं के बजाय प्रतिनिधि का उपयोग करने पर विचार कर सकते हैं। यहां स्लाइड्स का एक अच्छा प्रो/कॉन सेट है: http://www.slideshare.net/360conferences/nsnotificationcenter-vs-appdelegate

+0

मुझे लगता है कि इस मामले के लिए सूचनाएं ठीक हैं, क्योंकि मैं दृश्य परत पर एनीमेशन को अतुल्यकालिक रूप से ट्रिगर करता हूं। मैं परीक्षण कोड और मुख्य वर्ग को सरल बनाने के लिए, मेरी कस्टम अधिसूचना कक्षा को इंजेक्शन देने से बचने की कोशिश कर रहा था, लेकिन ऐसा लगता है कि अब तक यह एकमात्र विकल्प है। – pgb

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