Java 用JMockit模拟私有静态字段?

Java 用JMockit模拟私有静态字段?,java,unit-testing,jmockit,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 (actualBackupFi

我有一门课,如下所示

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;
            }
       }
    }
}
所以,基本上,我想通过模拟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"
  }
运行上述测试时,我在ClassA中得到myDir字段的NullPointerException-因此它看起来没有被正确模拟?

尝试以下方法:

new Expectations {{
  invoke(File.class, "list", null, null);
  returns(files);
}}
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);
}

上述措施应该有效。请注意,直接测试
private
方法(或访问
private
字段)被认为是不好的做法,因此我在这里避免了这种做法。此外,最好避免模拟
文件
类。相反,只测试您的
public
方法,并使用实际文件,而不是模拟文件系统。

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

Deencapsulation.setField(ClassA, "File", your_desired_value);

谢谢,但是文档说invoke是为了调用一个静态方法-文件上的list()不是静态的-似乎不起作用。非常好,感谢你的帮助Rogerio,这通过对你的代码做一个小改动就起作用了-@mock File myDir必须改成@mock(methods={“list”})File myDir才能工作。我认为这可能是因为Deencapsualtion.invoke调用在某个时候可能需要一个真正的文件对象,模拟所有的方法似乎会干扰某些东西。我是新用户,所以不能投票支持你,否则我会!伟大的模拟
文件
确实会导致意外的失败,至少在较旧版本的JMockit中是如此。我用您的更改编辑了答案。@Rogério,上面创建模拟对象(
myDir
)的方法导致引用为
null
,导致
myDir.list()
失败,出现
NPE
。知道为什么吗?@mystarrocks本地模拟字段不再受支持。测试已更新为使用模拟参数。请不要使用实际文件。这样做会占用一个文件系统,该文件系统会添加竞争条件,并将通常在.01秒内执行的快速执行单元测试转换为在.5秒内执行的慢速测试。(现在想象一下有一千个单元测试,你会发现你会有一个缓慢的反馈循环,这将破坏快速执行单元测试的起点。)我发现
Deencapsulation
类在JMockit 1.45中不再有
setField()
(尽管1.3.0有)。请不要直接使用Deencapsulation。这被认为是不好的做法。是否有
去封装的替代品
?我需要在
@Tested
对象中设置私有静态最终字段。