使用Java Reflection访问测试用例中的受保护方法

Accessing protected method in test case using Java Reflection

我试图使用Java Reflection获取和调用驻留在不同类中的受保护方法以及不同的包。

包含受保护方法的类:

1
2
3
4
5
6
7
8
package com.myapp;

public class MyServiceImpl {

   protected List<String> retrieveItems(String status) {
         // Implementation
   }
}

通话课程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package xxx.myapp.tests;

import com.myapp.MyServiceImpl;

public class MyTestCase {

    List<String> items;

    public void setUp() throws Exception {

         MyServiceImpl service = new MyServiceImpl();
         Class clazz = service.getClass();

         // Fails at the next line:
         Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");

         // How to invoke the method and return List<String> items?
         // tried this but it fails?
         retrieveItems.invoke(clazz,"S");
    }
}

编译器抛出此异常:

1
java.lang.NoSuchMethodException: com.myapp.MyServiceImpl.retrieveItems()

您的代码的问题是getDeclaredMethod函数通过名称和参数类型查找函数。随着电话

1
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");

代码将查找没有参数的方法retrieveItems()。你正在寻找的方法确实采用了一个参数,一个字符串,所以你应该调用

1
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);

这将告诉Java搜索retrieveItems(String),这正是您正在寻找的。


为什么不简单地创建一个派生类,而不是使用那些棘手的反射内容,它可以访问受保护的方法?

请参阅在单元测试中使用反射是不好的做法?进一步的想法。


如果将测试用例放在同一个包中(com.myapp而不是com.myapp.tests),则可以访问受保护的(和默认包级别)成员。

然后你可以直接打电话给service.retrieveMembers(status)

如果您尝试将源与测试分开,通常最好使用不同的源目录(例如src目录和test目录)。


您应该使用链接到创建的对象而不是在invoke方法中链接到类,并使用Method.setAccessible(true)调用来解锁访问:

1
2
3
4
5
6
7
public void setUp() throws Exception {
    MyServiceImpl service = new MyServiceImpl();
    Class< ? > clazz = service.getClass();
    Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
    retrieveItems.setAccessible(true);
    items = (List<String>)retrieveItems.invoke(service,"S");
}

不需要反射或继承:

MyTestCase放在包com.myapp下,因为范围'protected'也是'package'。
然后MyTestCase可以访问MyServiceImpl的受保护方法。