zer*_*n23 10 java reflection methods final
在尝试编写测试用例时会出现这个问题.Foo是框架库中的一个类,我没有源代码访问权限.
public class Foo{
public final Object getX(){
...
}
}
Run Code Online (Sandbox Code Playgroud)
我的申请会
public class Bar extends Foo{
public int process(){
Object value = getX();
...
}
}
Run Code Online (Sandbox Code Playgroud)
由于其他依赖性,我无法创建Foo对象,因此单元测试用例无法初始化.当值为null时,BarTest抛出空指针.
public class BarTest extends TestCase{
public testProcess(){
Bar bar = new Bar();
int result = bar.process();
...
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法可以使用反射api将getX()设置为非final?或者我该如何进行测试?
Cur*_*tis 19
因为这是google中"覆盖最终方法java"的最佳结果之一.我以为我会离开我的解决方案.这个类使用示例"Bagel"类和一个免费使用的javassist库来显示一个简单的解决方案:
/**
* 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 otherwise you will get exceptions.
*/
package packagename;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Modifier;
/**
* A simple class to show how to use the library
*/
public class TestCt {
/**
* The starting point for the application
*/
public static void main(String[] args) {
// in order for us to override the final method we must manipulate the class using the Javassist library.
// we need to do this FIRST because once we initialize the class it will no longer be editable.
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 and include the options in the output
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();
}
// now that we have edited the classes with the new methods, we can create an instance and see if it worked
// create a new instance of BagelWithOptions
BagelWithOptions myBagel = new BagelWithOptions();
// give it some options
myBagel.setOptions("cheese, bacon and eggs");
// print the description of the bagel to the console.
// This should now use our new code when calling getDescription() which will include the options in the output.
System.out.println("My bagel is: " + myBagel.getDescription());
// The output should be:
// **My bagel is: a plain bagel with cheese, bacon and eggs**
}
/**
* A plain bagel class which has a final method which we want to override
*/
public static class Bagel {
/**
* return a description for this bagel
*/
public final String getDescription() {
return "a plain bagel";
}
}
/**
* A sub class of bagel which adds some extra options for the bagel.
*/
public static class BagelWithOptions extends Bagel {
/**
* A string that will contain any extra options for the bagel
*/
String options;
/**
* Initiate the bagel with no extra options
*/
public BagelWithOptions() {
options = "nothing else";
}
/**
* Set the options for the bagel
* @param options - a string with the new options for this bagel
*/
public void setOptions(String options) {
this.options = options;
}
/**
* return the current options for this bagel
*/
public String getOptions() {
return options;
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以创建另一个可以在测试中覆盖的方法:
public class Bar extends Foo {
protected Object doGetX() {
return getX();
}
public int process(){
Object value = doGetX();
...
}
}
Run Code Online (Sandbox Code Playgroud)
那么,你可以在BarTest中覆盖doGetX.
| 归档时间: |
|
| 查看次数: |
14791 次 |
| 最近记录: |