用JMockit模拟私有静态字段?

use*_*917 10 java unit-testing jmockit

我有一个类似以下的课程;

class ClassA {
    private static File myDir;

    // myDir is created at some stage

    private static String findFile(final String fileName) {
       for (final String actualBackupFileName : myDir.list()) {
           if (actualBackupFileName.startsWith(removeExtensionFrom(backupFile))) {
               return actualBackupFileName;
            }
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,基本上,我想通过模拟File类来测试这个类,以便在调用list()时它返回我在我的测试类中定义的字符串列表.

我已经得到了以下内容,但它在一分钟内没有工作,可能有一些明显我做错了 - 我是JMockit的新手 - 非常感谢任何帮助!

@Mocked("list") File myDir;

@Test
  public void testClassA() {
    final String[] files = {"file1-bla.txt"};

    new NonStrictExpectations() {{
      new File(anyString).list(); 
      returns(files);
   }};

   String returnedFileName = Deencapsulation.invoke(ClassA.class, "findFile","file1.txt");

   // assert returnedFileName is equal to "file1-bla.txt"
  }
Run Code Online (Sandbox Code Playgroud)

运行上面的测试时,我得到了ClassA中myDir字段的NullPointerException - 所以看起来它没有被正确模拟?

小智 11

您可以使用Deencapsulation类中的setField方法.注意以下示例:

Deencapsulation.setField(ClassA, "File", your_desired_value);
Run Code Online (Sandbox Code Playgroud)

  • 我发现 **JMockit 1.45** 中的 `Deencapsulation` 类不再有 `setField()`(尽管 1.3.0 有)。 (2认同)
  • 是否有“解封装”的替代品?我需要在“@Tested”对象中设置私有静态最终字段。 (2认同)

Rog*_*rio 10

JMockit(或任何其他模拟工具)不模拟字段或变量,它模拟类型(类,接口等).这些类型的实例存储在被测试代码中是不相关的.

示例测试ClassA:

@Test
public void testClassA(@Mocked File myDir)
{
    new Expectations() {{ myDir.list(); result = "file1-bla.txt"; }};

    String returnedFileName = new ClassA().publicMethodThatCallsFindFile("file1.txt");

    assertEquals("file1-bla.txt", returnedFileName);
}
Run Code Online (Sandbox Code Playgroud)

以上应该有效.请注意,private直接测试方法(或访问private字段)被认为是不好的做法,所以我在这里避免使用它.此外,最好避免嘲笑File班级.相反,只测试您的public方法,并使用实际文件而不是模拟文件系统.