2009-04-14 14 views
8

परीक्षण प्रश्न लिखने की कोशिश करते समय यह प्रश्न उठता है। फू फ्रेमवर्क लाइब्रेरी के भीतर एक कक्षा है जिसका मेरे पास स्रोत पहुंच नहीं है।प्रतिबिंब या अन्य माध्यमों के माध्यम से जावा अंतिम तरीकों को ओवरराइड करें?

public class Foo{ 
    public final Object getX(){ 
    ... 
    } 
} 

मेरी अनुप्रयोगों होगा

public class Bar extends Foo{ 
    public int process(){ 
    Object value = getX(); 
    ... 
    } 
} 

इकाई परीक्षण का मामला अन्य निर्भरता की वजह से initalize के रूप में मैं एक फू वस्तु नहीं बना सकते में असमर्थ है। बारटेस्ट एक शून्य पॉइंटर फेंकता है क्योंकि मान शून्य है।

public class BarTest extends TestCase{ 
    public testProcess(){ 
    Bar bar = new Bar();   
    int result = bar.process(); 
    ... 
    } 
} 

वहाँ एक रास्ता मैं प्रतिबिंब एपीआई का उपयोग कर सकते गैर अंतिम करने के लिए getX() स्थापित करने के लिए है? या मुझे परीक्षण के बारे में कैसे जाना चाहिए?

उत्तर

5

आप एक और तरीका है जो आप अपने परीक्षण में रद्द कर सकते थे बना सकते हैं: तो

public class Bar extends Foo { 
    protected Object doGetX() { 
    return getX(); 
    } 
    public int process(){ 
    Object value = doGetX(); 
    ... 
    } 
} 

, आप BarTest में doGetX रद्द कर सकते थे।

0

यदि आपका यूनिट टेस्ट केस अन्य निर्भरताओं के कारण फू नहीं बना सकता है, तो यह एक संकेत हो सकता है कि आप अपना यूनिट परीक्षण पहले स्थान पर नहीं बना रहे हैं।

यूनिट परीक्षण एक ही परिस्थिति में परीक्षण कोड चलाने के लिए परीक्षण करने के लिए हैं, इसलिए मैं आपके परीक्षणों के अंदर एक ही उत्पादन वातावरण को पुनर्जीवित करने का सुझाव दूंगा। अन्यथा, आपके परीक्षण पूरा नहीं होंगे।

+6

यह यूनिट परीक्षण नहीं है। यूनिट परीक्षण कोड की बेहद दानेदार इकाइयों के लिए हैं। आप जो वर्णन कर रहे हैं वह एकीकरण परीक्षण या संभवतः कार्यात्मक परीक्षणों की तरह लगता है। –

+0

जरूरी नहीं है; मैं उन विशिष्ट परिस्थितियों को नहीं जानता जिसमें वह काम कर रहे हैं (यानी अन्य वर्ग, डीबी, इत्यादि), लेकिन कुछ परीक्षण हैं जो आप कई कक्षाओं के साथ एक साथ कर सकते हैं - उदाहरण के लिए, यदि आप बाहरी पुस्तकालय का उपयोग कर रहे हैं, तो यह है यह मानने के लिए ठीक है कि यह ठीक काम कर रहा है और अपने परीक्षणों में अपने सभी क्लिक्स का उपयोग करें। – Seb

+3

हाँ, "कुछ परीक्षण आप एक साथ कई कक्षाओं के साथ कर सकते हैं"। वे यूनिट परीक्षण नहीं हैं। अभी भी उपयोगी, और महत्वपूर्ण है, लेकिन वे ** यूनिट ** परीक्षण नहीं हैं। –

2

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

+0

क्या आप पहलू उन्मुख उर्फ ​​एओपी का जिक्र कर रहे हैं? कोई विचार अगर एओपी गैर-फाइनल तक पहुंच बदल सकता है? – zeroin23

+1

मैं वास्तव में एओपी का अर्थ नहीं था, यकीन नहीं कि यह कर सकता है, मैं http://jakarta.apache.org/bcel/ की तर्ज पर और सोच रहा था। हालांकि, अगर कुछ करना मुश्किल है तो शायद इसके लिए एक कारण है ... और आम तौर पर कठिन चीजें नहीं की जानी चाहिए :-) – TofuBeer

0

तो चर getX() द्वारा वापस नहीं है final आप तकनीक का उपयोग कर सकते हैं Reflection के माध्यम से private चर के मूल्य को बदलने के लिए What’s the best way of unit testing private methods? में विस्तार से बताया।

+0

दुख की बात है, यह अंतिम चिह्नित है ... वैसे भी – zeroin23

0
public class Bar extends Foo{ 
    public int process(){ 
    Object value = getX(); 
    return process2(value); 
    } 
    public int process2(Object value){ 
    ... 
    } 
} 

public class BarTest extends TestCase{ 
    public testProcess(){ 
    Bar bar = new Bar(); 
    Mockobj mo = new Mockobj();  
    int result = bar.process2(mo); 
    ... 
    } 
} 

जो मैंने अंततः उपरोक्त किया था। यह थोड़ा बदसूरत है ... जेम्स समाधान निश्चित रूप से इससे बेहतर है ...

10

चूंकि यह Google में "अंतिम विधि जावा ओवरराइड" के शीर्ष परिणामों में से एक था। मैंने सोचा कि मैं अपना समाधान छोड़ दूंगा। यह वर्ग एक उदाहरण बैगेल क्लास का उपयोग करके एक सरल समाधान दिखाता है और जावास्क्रिप्ट लाइब्रेरी का उपयोग करने के लिए एक निःशुल्क समाधान दिखाता है:

//This class shows how you can override a final method of a super class using the Javassist's bytecode toolkit 
//The library can be found here: http://jboss-javassist.github.io/javassist/ 
// 
//The basic idea is that you get the super class and reset the modifiers so the modifiers of the method don't include final. 
//Then you add in a new method to the sub class which overrides the now non final method of the super class. 
// 
//The only "catch" is you have to do the class manipulation before any calls to the class happen in your code. So put the 
//manipulation as early in your code as you can. 

package packagename; 

import javassist.ClassPool; 
import javassist.CtClass; 
import javassist.CtMethod; 
import javassist.CtNewMethod; 
import javassist.Modifier; 

public class TestCt { 

    public static void main(String[] args) { 
     try 
     { 
      // get the super class 
      CtClass bagel = ClassPool.getDefault().get("packagename.TestCt$Bagel"); 

      // get the method you want to override 
      CtMethod originalMethod = bagel.getDeclaredMethod("getDescription"); 

      // set the modifier. This will remove the 'final' modifier from the method. 
      // If for whatever reason you needed more than one modifier just add them together 
      originalMethod.setModifiers(Modifier.PUBLIC); 

      // save the changes to the super class 
      bagel.toClass(); 

      // get the subclass 
      CtClass bagelsolver = ClassPool.getDefault().get("packagename.TestCt$BagelWithOptions"); 

      // create the method that will override the super class's method 
      CtMethod overrideMethod = CtNewMethod.make("public String getDescription() { return super.getDescription() + \" with \" + getOptions(); }", bagelsolver); 

      // add the new method to the sub class 
      bagelsolver.addMethod(overrideMethod); 

      // save the changes to the sub class 
      bagelsolver.toClass(); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 

     BagelWithOptions myBagel = new BagelWithOptions(); 

     myBagel.setOptions("cheese, bacon and eggs"); 

     System.out.println("My bagel is: " + myBagel.getDescription()); 
    } 

    public static class Bagel { 
     public final String getDescription() { 
      return "a plain bagel"; 
     } 
    } 

    public static class BagelWithOptions extends Bagel { 
     String options; 

     public BagelWithOptions() { 
      options = "nothing else"; 
     } 

     public void setOptions(String options) { 
      this.options = options; 
     } 

     public String getOptions() { 
      return options; 
     } 
    } 
} 
संबंधित मुद्दे