【问题标题】:Accessing protected method in test case using Java Reflection使用 Java 反射访问测试用例中的受保护方法
【发布时间】: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()

【问题讨论】:

    标签: java reflection junit protected


    【解决方案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-&gt;main-&gt;java 包含所有代码。 src-&gt;test-&gt;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 的回答对其进行访问。
      猜你喜欢
      • 2010-10-18
      • 2012-01-22
      • 2017-05-30
      • 1970-01-01
      • 2019-08-18
      • 2011-09-12
      • 2020-07-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多