mockito - मॉकिटो केवल सुपरक्लास की विधि का आह्वान कैसे करें




(5)

ChildService.save () विधि से कोड को दोबारा विधि में दोबारा करने पर विचार करें और ChildService.save () का परीक्षण करने की बजाय नई विधि का परीक्षण करें, इस तरह आप सुपर विधि को अनावश्यक कॉल से बचेंगे।

उदाहरण:

class BaseService {  
    public void save() {...}  
}

public Childservice extends BaseService {  
    public void save(){  
        newMethod();    
        super.save();
    }
    public void newMethod(){
       //some codes
    }
} 

मैं कुछ परीक्षणों में मॉकिटो का उपयोग कर रहा हूं।

मेरे पास निम्नलिखित कक्षाएं हैं:

class BaseService {  
    public void save() {...}  
}

public Childservice extends BaseService {  
    public void save(){  
        //some code  
        super.save();
    }  
}   

मैं ChildService केवल दूसरे कॉल ( super.save ) को ChildService करना चाहता ChildService । पहली कॉल को वास्तविक विधि को कॉल करना होगा। क्या ऐसा करने के लिए कोई रास्ता है?


इसका कारण यह है कि आपकी बेस क्लास सार्वजनिक-एड नहीं है, तो मॉकिटो दृश्यता के कारण इसे रोक नहीं सकता है, यदि आप बेस क्लास को सार्वजनिक के रूप में बदलते हैं, या @ ओवरराइड में उप-वर्ग (सार्वजनिक रूप में) करते हैं, तो मॉकिटो इसे सही तरीके से मॉक कर सकता है।

public class BaseService{
  public boolean foo(){
    return true;
  }
}

public ChildService extends BaseService{
}

@Test
@Mock ChildService childService;
public void testSave() {
  Mockito.when(childService.foo()).thenReturn(false);

  // When
  assertFalse(childService.foo());
}

नहीं, मॉकिटो इसका समर्थन नहीं करता है।

यह वह उत्तर नहीं हो सकता है जिसे आप ढूंढ रहे हैं, लेकिन जो भी आप देख रहे हैं वह डिज़ाइन सिद्धांत लागू नहीं करने का एक लक्षण है:

विरासत पर रचना का पक्ष लें

यदि आप सुपर क्लास को विस्तारित करने की बजाय रणनीति निकालते हैं तो समस्या खत्म हो जाती है।

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

मेरा सुझाव है कि आप रिफैक्टरिंग के लिए जाएं, लेकिन अगर यह कोई विकल्प नहीं है तो आप कुछ गंभीर हैकिंग मज़े के लिए हैं।


भले ही मैं पूरी तरह से iwein प्रतिक्रिया से सहमत हूं (

विरासत पर रचना का पक्ष लें

), मैं मानता हूं कि कुछ बार विरासत सिर्फ प्राकृतिक लगती है, और मुझे यूनिट परीक्षण के लिए इसे तोड़ने या दोबारा नहीं लग रहा है।

तो, मेरा सुझाव:

/**
 * BaseService is now an asbtract class encapsulating 
 * some common logic callable by child implementations
 */
abstract class BaseService {  
    protected void commonSave() {
        // Put your common work here
    }

    abstract void save();
}

public ChildService extends BaseService {  
    public void save() {
        // Put your child specific work here
        // ...

        this.commonSave();
    }  
}

और फिर, इकाई परीक्षण में:

    ChildService childSrv = Mockito.mock(ChildService.class, Mockito.CALLS_REAL_METHODS);

    Mockito.doAnswer(new Answer<Void>() {
        @Override
        public Boolean answer(InvocationOnMock invocation)
                throws Throwable {
            // Put your mocked behavior of BaseService.commonSave() here
            return null;
        }
    }).when(childSrv).commonSave();

    childSrv.save();

    Mockito.verify(childSrv, Mockito.times(1)).commonSave();

    // Put any other assertions to check child specific work is done

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

 public Childservice extends BaseService {
    public void save(){
        //some code
        superSave();
    }

    void superSave(){
        super.save();
    }
}