为什么 file.exists() 检查在 mockito 参数匹配器中的 file.delete() 之后执行?

Why is the file.exists() check executed after the file.delete() in mockito argument matcher?

在我的代码中,我尝试测试一个文件,该文件的路径以字符串形式提供给如下方法:

TestClass testClass = spy(new TestClass());

@Test
public void test() {
    testClass.someMethod();


    doNothing().when(testClass).someOtherMethod(any(String.class));
    Mockito.verify(testClass, times(1)).someOtherMethod(argThat(this::checkFile));
}

private boolean checkFile(final String filePath) {
    boolean fileLegit = true;

    File file = new File(filePath);
    assertThat(file).exists();

    try {
        // Some testing on the file
    } catch (IOException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) {
        fileLegit = false;
    }

    file.delete(); // <- Trying to delete

    return fileLegit;
}

这里我得到以下异常:

java.lang.AssertionError: 
Expecting file:
  <path\to\file>
to exist

当我删除 file.delete() 时,一切正常,但文件没有被删除(很明显)。不过我需要在测试后删除它,所以你知道为什么会发生这种情况以及如何解决它吗?

这里是 TestClass 对象,因为有些人对它很感兴趣(盲码,但你明白了):

public class TestClass {
    public void someMethod() {
        List<String> content = new ArrayList<>();
        content.add("test");

        Path path = Paths.get(/* Choose a path */);

        if (!Files.exists(path)) {
            Files.createFile(path);
        }

        Files.write(path, content, StandardCharsets.UTF_8);

        someOtherMethod(path.toString());
    }

    void someOtherMethod(String filepath) {
        System.out.println(filepath);
    }
}

我假设 testClass 是您的 TestClass 对象上的 spy,即使您的示例没有提及这一点。请注意,如果可以,您应该尽量将 spies 的使用限制在遗留代码中。

您的问题与 运行 单元测试时 checkFile 方法被调用两次有关。您编写此代码的前提是您的方法仅被调用一次,但在这种情况下 Mockito 并非如此。

您可以通过在您的方法中添加 breakpointSystem.out 来轻松验证。

要解决此问题,请将文件删除逻辑与匹配器分开。您可能想要添加一个清理 (@AfterEach) 方法。