2009-07-06 15 views
6

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

- (void) navigate:(NavContext *)context { 
    Destination * dest = [[Destination alloc] initWithContext:context]; 
    if (context.isValid) { 
    [dest doSomething]; 
    } else { 
    // something else 
    } 
    [dest release]; 
} 

क्या मैं सत्यापित करना चाहते हैं कि यदि context.isValid सच है, कि DoSomething गंतव्य पर कहा जाता है, लेकिन मुझे नहीं पता कि परीक्षण करने के लिए कैसे (या कि अगर भी है संभव) ओसीएमॉक या किसी अन्य पारंपरिक परीक्षण विधियों का उपयोग करके, क्योंकि ऑब्जेक्ट पूरी तरह से विधि के दायरे में बनाया गया है। क्या मैं इस बारे में गलत तरीके से जा रहा हूं?

उत्तर

5

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

यह करने के लिए शायद एक

-(void) navigate:(NavContext *)context destination:(Destination *)dest; 

विधि लागू करने के लिए किया जाएगा स्पष्ट तरीका। निम्न के -(void) navigate:(NavContext *)context के कार्यान्वयन बदलें:

- (void) navigate:(NavContext *)context { 
    Destination * dest = [[Destination alloc] initWithContext:context]; 
    [self navigate:context destination:dest]; 
    [dest release]; 
} 

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

+0

यह सबसे आसान जवाब प्रतीत होता है, लेकिन यह गंतव्य वस्तु को कई क्षेत्रों में रहने के लिए थोड़ा गन्दा लगता है आसान परीक्षण का समर्थन करने के लिए, वास्तव में कहीं और इसकी आवश्यकता नहीं है। मुझे लगता है कि समझौता कहीं कहीं किया जाना चाहिए :) – Kevlar

+0

हाँ; यदि आप एक अलग गंतव्य वस्तु को प्रतिस्थापित करने में सक्षम होना चाहते हैं, तो आपको इसे पास करने का कोई तरीका होना चाहिए। यह ऐसा करने का सबसे साफ तरीका है जिसे मैं जानता हूं। –

0

method swizzling जैसी रोचक तकनीकों का उपयोग करके यह पूरी तरह से संभव है, लेकिन शायद यह गलत तरीके से इसके बारे में जा रहा है। यदि इकाई परीक्षण से doSomething का आह्वान करने के प्रभावों का पालन करने का कोई तरीका नहीं है, तो यह तथ्य नहीं है कि यह doSomething कार्यान्वयन विस्तार का आह्वान करता है?

+0

मुझे लगता है कि अगर यह परीक्षण नहीं किया जाता है तो यह एक बड़ा सौदा नहीं है। मैं अभी भी टीडीडी/यूनिट परीक्षण के लिए कुछ नया हूं इसलिए मुझे अभी तक सभी बेहतरीन प्रथाओं को नहीं पता है :) – Kevlar

1

मैं क्या सत्यापित करना चाहता हूं कि अगर context.isValid सत्य है , ऐसा कुछ है जिसे

पर कुछ कहा जाता है, मुझे लगता है कि आप यहां गलत चीज़ का परीक्षण कर सकते हैं। आप सुरक्षित रूप से मान सकते हैं (मुझे उम्मीद है) कि बूलियन स्टेटमेंट ओबीजेसी में सही तरीके से काम करते हैं। क्या आप इसके बजाय संदर्भ ऑब्जेक्ट का परीक्षण नहीं करना चाहते हैं? यदि संदर्भ .isValid तो आपको गारंटी है कि [dest doSomething] शाखा निष्पादित हो जाती है।

+0

मैं इस ऑब्जेक्ट में संदर्भ ऑब्जेक्ट का मज़ाक उड़ा रहा हूं क्योंकि मुझे परवाह नहीं है कि यह कैसे बनाया जाता है, मुझे लगता है कि विधि संदर्भ की गुणों के आधार पर सही चीज़ करती है। – Kevlar

+0

आगे, अगर नेविगेट के कार्यान्वयन: कभी भी परिवर्तन होता है, तो वह अभी भी यह सत्यापित करना चाहता है कि कुछ ऐसा कहा जाता है। –

+0

आह पर्याप्त मेला, मैं थोड़ा छोटा देखा जा रहा था। मुझे बीजे होमर के दृष्टिकोण पसंद है। – EightyEight

0

मैं इस स्थिति में कारखाने तरीकों का उपयोग करना पसंद है।

id destinationMock = [OCMock mockForClass:FakeDestination.class]; 
// do the swizzle 
[FakeDestination setSharedInstance:destinationMock]; 
[[destinationMock expect] doSomething]; 
// Call your method 
[destinationMock verify]; 
:

#import "Destination+Factory.h" 

@interface FakeDestination : Destination 
+ (id)sharedInstance; 
+ (void)setSharedInstance:(id)sharedInstance; 
// Note! Instance method! 
- (Destination *)destinationWithContext:(NavContext *)context; 
@end 

@implementation FakeDestination 
+ (id)sharedInstance 
{ 
    static id _sharedInstance = nil; 
    if (!_sharedInstance) 
    { 
     _sharedInstance = [[FakeDestination alloc] init]; 
    } 
    return _sharedInstance; 
} 
+ (void)setSharedInstance:(id)sharedInstance 
{ 
    _sharedInstance = sharedInstance; 
} 
// Overrides 
+ (Destination *)destinationWithContext:(NavContext *)context { [FakeDestination.sharedInstance destinationWithContext:context]; } 
// Instance 
- (Destination *)destinationWithContext:(NavContext *)context { return nil; } 
@end 

एक बार जब आप इसे सेट अप, तो आप सिर्फ swizzle the class methods करने के लिए + (Destination *)destinationWithContext:(NavContext *)context;

अब आप करने के लिए सेट कर रहे हैं की जरूरत है:

@interface Destination(Factory) 
+ (Destination *)destinationWithContext:(NavContext *)context; 
@end 

@implementation Destination(Factory) 
+ (Destination *)destinationWithContext:(NavContext *)context 
{ 
    return [[Destination alloc] initWithContext:context]; 
} 
@end 

मैं तो एक FakeClass बनाने

यह सामने कोडिंग भी पर्याप्त मात्रा में है, लेकिन यह बहुत पुन: प्रयोज्य है।

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