【问题标题】:Access a private field for a junit test访问 junit 测试的私有字段
【发布时间】:2015-03-07 14:23:49
【问题描述】:

我正在尝试从一个类初始化一个私有字段,以便对其方法进行单元测试。为此,我正在使用反射,但我总是收到 IllegalArgumentException,而且我不明白我做错了什么。

我的代码如下所示:

public class MyClass {

    private BufferedReader reader;

    public void methodToTest(){
        doSomethingwith(reader);
    }

}

public class testClass {

    @Test
    public void testMethod() {
        Field reader = MyClass.class.getDeclaredField("reader");
        reader.setAccessible(true);
        StringReader stringReader = new StringReader("some string");
        BufferedReader readerToSet = new BufferedReader(stringReader);
        reader.set(readerToSet, readerToSet);
        MyClass instance = new MyClass();
        instance.methodToTest();
    }

}

我在尝试运行测试时收到此错误:

Can not set java.io.BufferedReader field MyClass.receiveReader to java.io.BufferedReader

我还尝试从类中获取字段的值并设置给读者。但是该值返回 null,我仍然收到相同的错误消息。

知道如何初始化字段以便测试方法吗?

【问题讨论】:

    标签: java unit-testing reflection field


    【解决方案1】:

    你必须实例化对象你可以设置它的字段! (而且您拼错了 BufferedReader 参考。)

    Field reader = MyClass.class.getDeclaredField("reader");
    reader.setAccessible(true);
    MyClass mc = new MyClass();
    StringReader stringReader = new StringReader("some string");
    BufferedReader readerToSet = new BufferedReader(stringReader);
    reader.set(mc, readerToSet);
    mc.methodToTest();
    

    【讨论】:

      【解决方案2】:

      @kocko 的回答在大多数情况下都是正确的。但是,如果您不想显示实现细节,您可以不为您的字段设置访问级别修饰符(default 访问级别)。

      因此,在您的情况下,字段声明应如下所示:

      public class MyClass {
          BufferedReader reader;
          ...
      }
      

      然后确保您的测试与您的代码位于同一包中,但位于test 目录中。如果一切正常,您将能够在没有任何黑客攻击的情况下访问它。

      注意:default 访问级别意味着该事物仅在类和包内可见。

      【讨论】:

      • 我看不到 @kocko 的回答
      【解决方案3】:

      您可以为此使用 Mockito (org.mockito.internal.util.reflection.Whitebox)

      Whitebox.setInternalState(object, "fieldName", fieldValue);
      

      【讨论】:

      • Whitebox 位于 Mockito 的 internal 包中,自 Mockito 2.6.2 以来不再工作。您可以改用org.mockito.internal.util.reflection.FieldSetter,但这也在internal 包中。似乎 Mockito 不希望您操作私有字段,但在内部,这些方法与 @laune 的解决方案执行相同的操作
      【解决方案4】:

      使用 apache.commons.lang3

      import org.apache.commons.lang3.reflect.FieldUtils;
      
      FieldUtils.writeField(myObject, "anyProperty", 420/*any value*/, true);
      
      FieldUtils.readField(myObject, "anyProperty", true);
      

      【讨论】:

        【解决方案5】:

        如果你使用的是spring,你也可以使用spring-test。

        import org.springframework.test.util.ReflectionTestUtils;
        
        ReflectionTestUtils.setField(notificationService, "timeToLive", 90L);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-05
          • 1970-01-01
          • 2012-06-07
          • 1970-01-01
          • 1970-01-01
          • 2016-10-25
          相关资源
          最近更新 更多