使用 Java 反射访问测试用例中的受保护方法
Posted
技术标签:
【中文标题】使用 Java 反射访问测试用例中的受保护方法【英文标题】:Accessing protected method in test case using Java Reflection 【发布时间】:2011-06-07 13:03:07 【问题描述】:我正在尝试使用 Java 反射获取和调用驻留在不同类和不同包中的受保护方法。
包含受保护方法的类:
package com.myapp;
public class MyServiceImpl
protected List<String> retrieveItems(String status)
// Implementation
调用类:
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");
编译器抛出这个异常:
java.lang.NoSuchMethodException: com.myapp.MyServiceImpl.retrieveItems()
【问题讨论】:
【参考方案1】:如果您将测试用例放在同一个包中(com.myapp
而不是com.myapp.tests
),他们将可以访问 protected(和 default 包级别)成员。
那你可以直接拨打service.retrieveMembers(status)
。
如果您试图将源代码与测试分开,通常最好使用不同的源目录(例如src
目录和test
目录)。
【讨论】:
如果测试在同一个包中,那么你编译的类文件很可能会在同一个目标目录中,这会使任何部署文件与一堆测试类文件膨胀,除非你去通过您拥有的每个包/项目并为目标目录定义排除规则。在我看来不是一个好主意。 这就是您使用不同的源目录进行测试的原因。这是 maven 等工具的标准工作方式。 是的,我误解了你的帖子。我明白你现在在说什么了,谢谢!【参考方案2】:您应该在调用方法中使用创建对象的链接而不是类的链接,并使用 Method.setAccessible(true) 调用来解锁访问:
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");
【讨论】:
【参考方案3】:不需要反射或继承:
将您的MyTestCase
放在package com.myapp
下,因为“protected”范围也是“package”。
那么MyTestCase
就可以访问MyServiceImpl
的protected方法了。
【讨论】:
如果测试在同一个包中,那么你编译的类文件很可能会在同一个目标目录中,这会使任何部署文件与一堆测试类文件膨胀,除非你去通过您拥有的每个包/项目并为目标目录定义排除规则。在我看来这不是一个好主意。 @SandySimonton,可以实现。我们可以使我们的项目结构如下(maven):src->main->java
包含所有代码。 src->test->java
包含所有测试。【参考方案4】:
为什么不简单地创建一个可以访问受保护方法的派生类,而不是使用那些棘手的反射东西?
更多想法请见Is it bad practice to use Reflection in Unit testing?。
【讨论】:
-1 -- 它不回答根本问题。在 Java 中如何通过反射访问受保护的方法? @BrainSlugs83 重新阅读问题的标题。 OP 实际上想测试一些代码,但错误地认为他们需要使用反射。他们有一个 XY 问题。我的回答是针对他们真正的问题,而不是他们提出的解决方案。 -1 -- “我正在尝试使用 Java 反射获取和调用驻留在不同类和不同包中的受保护方法。”这就是意图;你怎么知道这不像学校作业?似乎告诉他创建一个派生类(这会导致更多的代码行)就像用“使用开罐器”来回答“我想用我的刀打开一罐金枪鱼”这个问题。【参考方案5】:您的代码的问题是getDeclaredMethod
函数通过名称和参数类型查找函数。随叫随到
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");
代码将查找不带参数的方法retrieveItems()
。你正在寻找的方法确实需要一个参数,一个字符串,所以你应该调用
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
这将告诉 Java 搜索 retrieveItems(String)
,这就是您要查找的内容。
【讨论】:
+1 - 这是异常标记的问题。检索到该方法后,必须按照@jk 的回答对其进行访问。以上是关于使用 Java 反射访问测试用例中的受保护方法的主要内容,如果未能解决你的问题,请参考以下文章