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");
}
} |
编译器抛出此异常:
您的代码的问题是getDeclaredMethod函数通过名称和参数类型查找函数。随着电话
1
| Method retrieveItems = clazz. getDeclaredMethod("retrieveItems"); |
代码将查找没有参数的方法retrieveItems()。你正在寻找的方法确实采用了一个参数,一个字符串,所以你应该调用
1
| Method retrieveItems = clazz. getDeclaredMethod("retrieveItems", String. class); |
这将告诉Java搜索retrieveItems(String),这正是您正在寻找的。
-
+1 - 这是异常标记的问题。一旦检索到该方法,就必须按照@jk的答案进行访问。
为什么不简单地创建一个派生类,而不是使用那些棘手的反射内容,它可以访问受保护的方法?
请参阅在单元测试中使用反射是不好的做法?进一步的想法。
-
+1 - 这是一种更明智的方法,IMO。
-
-1 - 它没有回答根问题。如何通过Java中的反射访问受保护的方法?
-
@ BrainSlugs83重读问题的标题。 OP实际上想要测试一些代码,但错误地认为他们需要使用反射。他们有XY问题。我的答案说明了他们的真正问题,而不是他们提出的解决方案。
-
-1 -"我试图使用Java Reflection获取和调用驻留在不同类中的受保护方法以及不同的包。"这是意图;你怎么知道这不像学校的作业?似乎告诉他创建一个派生类(导致更多代码行)就像回答"我想用刀开一罐金枪鱼"和"使用开罐器"这样的问题。
如果将测试用例放在同一个包中(com.myapp而不是com.myapp.tests),则可以访问受保护的(和默认包级别)成员。
然后你可以直接打电话给service.retrieveMembers(status)。
如果您尝试将源与测试分开,通常最好使用不同的源目录(例如src目录和test目录)。
-
如果测试在同一个包中,那么你编译的类文件很可能会在同一个目标目录中,这会使任何部署文件膨胀一堆测试类文件,除非你通过你拥有的每个包/项目和定义目标目录的排除规则。在我看来,这不是一个好主意。
-
这就是为什么你为测试使用不同的源目录。这是maven工作的标准方式。
-
是的,我误解了你的帖子。我明白你现在在说什么,谢谢!
您应该使用链接到创建的对象而不是在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的受保护方法。
-
如果测试在同一个包中,那么你编译的类文件很可能会在同一个目标目录中,这会使任何部署文件膨胀一堆测试类文件,除非你通过你拥有的每个包/项目和定义目标目录的排除规则。在我看来,这不是一个好主意。
-
@SandySimonton,它可以实现。我们可以使我们的项目结构如下(maven):src->main->java包含所有代码。 src->test->java包含所有测试。