2011-01-26 14 views
9

मैं अपने परीक्षणों में वस्तुओं को नकली करने के लिए EasyMock का उपयोग कर रहा हूं। लेकिन मैं अपने कोड में कहीं और बनाए गए ऑब्जेक्ट्स का नकल कैसे करूं? निम्नलिखित psudo कोड को देखो। मैं WebService # getPersonById का नकल करना चाहता हूं, मैं यह कैसे कर सकता हूं?मैं उन वस्तुओं का नकल कैसे करूं जो मैं अपने परीक्षणों में तत्काल नहीं कर सकता?

public class Person { 
    public Person find(int id) { 
    WebService ws = new WebService(); 
    return ws.getPersonById(id); 
    } 
} 

public class PersonTest { 
    testFind() { 
    // How do I mock WebService#getPersonById here? 
    } 
} 

उत्तर

0

मैं इसके बजाय JMockit का उपयोग कर समाप्त हुआ। इस वर्ग के सभी उदाहरणों का मज़ाक उड़ाने के लिए इसका समर्थन है।

+2

कहने के लिए खेद है, लेकिन यह एक शर्म की बात है। आईएमएचओ परीक्षण संचालित विकास के बारे में महान चीजों में से एक यह है कि आपको अपने डिजाइन को सोचने और पुनर्विचार करने के लिए मजबूर होना पड़ता है। ऐसा कुछ ढूंढना जो इंटरफेस के खिलाफ आसानी से टेस्टेबल नहीं है कोड गंध का एक अच्छा संकेत है। @ hvgotcodes ने एक अच्छा रास्ता निर्धारित किया है, आप कैसे अपना कोड अधिक रखरखाव, लचीला और टेस्टेबल बना सकते हैं। मैं इसे सिर्फ एक कामकाज के लिए फेंकना नहीं चाहता। –

9

मजाक आम तौर पर अच्छी तरह से काम करता है, तो आप अपनी सेवाओं तक तार की नियंत्रण और निर्भरता इंजेक्शन का प्रतिलोम का उपयोग करें। तो अपने व्यक्ति

public class Person() { 
    WebService ws = null; 

    // or use setters instead of constructor injection 
    Persion(WebService ws) { 
    this.ws = ws; 
    } 
    public Person find(int id) { 
    return ws.getPersonById(id); 
    } 
} 

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

अपने वास्तविक वातावरण में आईओसी कंटेनर, अब असली वेब सेवा इंजेक्षन जाएगा।

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

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

+0

+1 - यह लगभग ठीक है मैंने अपने (अब हटाए गए) उत्तर में क्या जोड़ा। –

+0

+1 अच्छा जवाब। एक शिक्षक होने का तरीका। – jwir3

+1

मुझे लगता है कि कोई कह सकता है कि एक कोड गंध है जब आप किसी वस्तु को नकल नहीं कर सकते हैं? :-) मुझे लगता है मुझे अपने कार्यान्वयन पर पुनर्विचार करना होगा। आपके भयानक उत्तर और उदाहरण के लिए बहुत धन्यवाद। – Sven

0

आपको सबसे पहले ws एक नकली बनाने की आवश्यकता है, आमतौर पर इसे इंजेक्शन द्वारा।

public abstract class Person() { 
    public Person find(int id) { 
    WebService ws = createWebService(); 
    return ws.getPersonById(id); 
    } 
    protected abstract WebService createWebService(); 
} 

तो फिर तुम में पर्ची कर सकते हैं और स्थापना के लिए EasyMock.expect का उपयोग वापसी

public class PersonTest() { 
    testFind() { 
    WebService mock = EasyMock.createMock(WebService.class); 
    Person p = new Persion() { 
     protected WebService createWebService() { 
     return mock; 
     } 
    } 
    EasyMock.expect(mock.getPersonById()).andReturn(dummyValue); 
    //Test code 
    } 
} 

तुम भी एक PersonImpl की आवश्यकता होगी वास्तविक विधि बना सके।

1

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

तत्काल सुविधा को भ्रमित न करें (मेरे पास Person ऑब्जेक्ट है, इसलिए मैं इसे और अधिक प्राप्त करने के लिए उपयोग करूँगा) रखरखाव के साथ।

3

EasyMock (या अन्य सभी मजाकिया एपीआई) के साथ ऐसा करने का कोई तरीका नहीं है।

public class PersonTest 
{ 
    @Test 
    public testFind(@Mocked final WebService ws) { 
     final int id = 123; 

     new NonStrictExpectations() {{ 
      ws.getPersonById(id); result = new Person(id); 
     }}; 

     Person personFound = new Person().find(id); 

     assertEquals(id, personFound.getId()); 
    } 
} 

तो, जब भी हम एक स्थिति है जहाँ एक इकाई परीक्षण पहली बार में नहीं लिखा जा सकता है में चलाने, हम अपने आप निष्कर्ष नहीं निकाल सकता है कि: JMockit के साथ, दूसरे हाथ पर, इस तरह के एक परीक्षण बहुत सरल और सुरुचिपूर्ण होगा परीक्षण के तहत कोड अवांछित है और इसे दोबारा करने की जरूरत है।कभी-कभी यह मामला होगा, लेकिन निश्चित रूप से हमेशा नहीं। शायद समस्या परीक्षण के तहत कोड में नहीं है, लेकिन इस्तेमाल होने वाले किसी विशेष मॉकिंग टूल की सीमाओं में है।

0

आप यहाँ PowerMock whenNew पद्धति का उपयोग करके

https://github.com/jayway/powermock/wiki/MockitoUsage#how-to-mock-construction-of-new-objects

अधिक उदाहरण कोशिश कर सकते हैं - http://www.programcreek.com/java-api-examples/index.php?api=org.powermock.api.mockito.PowerMockito

अपने कोड की तरह लग सकता है -

whenNew(WebService.class).withAnyArguments().thenReturn(yourMockInstanceToWebServiceClass);

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