JUnit Testing:调用父类保护方法

时间:2013-02-19 22:56:39

标签: java reflection methods junit protected

这是我的班级层次结构

abstract Class A
{
   int i = 0;
   protected init (String param1, String param2)
   {
       //do lots of common things based on param1, param2 and save data in i
   } 
}

然后有3-4个类实现A即

Class B extends A
{
    public B ()
    {
        super ();
    }

    public void performSomeAction ()
    {
        init (param1_specific_to_class_B, param2_specific_to_class_B); //calling parent class method 
        //do rest of teh random things
    }
}

现在,我正在尝试为A类编写JUnit测试。基本上我想测试任何init方法正在做的是否准确。我试过这个

Class clas = A.class;
B b = new B();

Method A_init;
A_init = clas.getDeclaredMethod("init", String.class, String.class);
A_init.invoke(b, param1_specific_to_class_B, param2_specific_to_class_B);

但它不起作用,我正在追踪异常

java.lang.IllegalAccessException: Class test.package.subpackage.ATest can not access a member of class package.subpackage.A with modifiers "protected"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
    at java.lang.reflect.Method.invoke(Method.java:578)
    at test.package.subpackage.ATest.initTest(ATest.java:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)

4 个答案:

答案 0 :(得分:4)

您可以将测试类放在与测试类相同的包中。因此测试类可以访问受保护的方法。

另一个更优雅的选择是使受保护的方法可访问:

A_init = clas.getDeclaredMethod("init", String.class, String.class);
A_init.setAccessible(true);
A_init.invoke(b, param1_specific_to_class_B, param2_specific_to_class_B);

希望它有所帮助。

答案 1 :(得分:1)

protected类的成员不是visible来自另一个包的类,除非它是前者的子类。

但是,在您的应用程序中,类test.package.subpackage.ATest正在尝试从package.subpackage中的另一个类访问受保护的方法,这会导致访问冲突。

尝试将ATest类放到某个位置,以便AATest属于同一个包。

答案 2 :(得分:1)

或者在TestClass中创建A的子类并通过公共方法公开受保护的方法:

public class TestClass extends TestCase(){

   // ...

   private class AChild extends A{
      public exposeInit (String param1, String param2){
         super.init(param1, param2);
      }
   }
}

现在你可以通过测试类AChild的初始化来测试A类的初始化。

我遇到了类似的问题,但是我们通过将设计改为组合而不是继承来解决它。

答案 3 :(得分:0)

也许我错过了一些东西,但是,因为B没有覆盖A.init()(至少从我能看到的)你可以去

B b = new B()
b.init(param1_specific_to_class_B, param2_specific_to_class_B)

如果B覆盖init(),

  1. 将所有内容放在同一个包中(正如其他人发布的那样)
  2. 如果无法或不希望更改包裹,您可能需要向B调用super.init()添加一种特殊方法。我将其命名为callSuperInitForUnitTests(),并在评论中明确指出这是单元测试的解决方法。