为什么我不应该嘲笑文件或路径

Why should I not be mocking File or Path

我一直在努力理解 jmockit Mocking API 支持的雷区 类。我发现我认为是 File 的错误,但问题只是说 "Don't mock a File or Path" 就关闭了,没有任何解释。这里有人可以帮助我理解为什么某些 类 不应该被嘲笑以及我应该如何解决这个问题。我试图通过错误报告为图书馆做出贡献,但我提交的每一份报告都让我更加困惑。请原谅我的无知,但如果有人能指出禁止模拟等的基本原理。我将不胜感激。

我不确定是否存在万无一失的规则列表。在这些事情上总是有一定程度的知识和品味。教条通常不是一个好主意。

我投票结束这个问题,因为我认为很多都是意见。

不过话虽如此,我还是会试试的。

单元测试应该是关于测试单个 classes,而不是 classes 之间的交互。这些称为集成测试。

如果您的对象正在调用其他远程对象(如服务),您应该将它们模拟为 return 测试所需的数据。这个想法是服务和他们的客户也应该在他们自己的单元测试中单独测试。在测试依赖于它们的 class 时,您无需重复这些。

在我看来,这条规则的一个例外是数据访问对象。在不连接到远程数据库的情况下测试其中一个是没有意义的。您的测试需要证明代码的正确运行。在数据访问对象的情况下,这需要数据库连接。这些应该被写成事务性的:种子数据库,执行测试,并反转测试的动作。完成后数据库应处于相同状态。

一旦您的数据访问对象被证明工作正常,所有使用它们的客户端都应该模拟它们。无需重新测试。

您不应该在 JVM 中模拟 classes。

您特别询问了关于 File 或 Stream 的原因 - 这是一个原因。接受或忽略它。

您不必测试 JVM classes,因为 Sun/Oracle 已经这样做了。你知道他们的工作。您希望 class 使用那些 classes,因为失败的测试将暴露必要文件不可用的事实。模拟不会告诉我我忘记将所需的文件放入我的 CLASSPATH 中。我想在测试期间找出答案,而不是在生产中。

另一个原因是单元测试也是文档。这是向其他人展示如何正确使用您的 class 的现场演示。

在单元测试中,您必须测试您的代码是否在做正确的事情。您可以模拟任何不是被测试的直接代码的外部代码。这是单元测试的严格定义,它假设有另一种称为集成测试的测试形式,稍后将进行。在集成测试中,您测试代码如何与外部元素交互,例如数据库或其他 Web 服务、网络或硬盘驱动器。

如果我有一段与对象(如文件)交互的代码,并且我的代码对该文件做了 3 件事,那么在我的单元测试中,我将测试我的代码是否完成了这三件事.

例如:

public void processFile(File f) {
    if (f.exists()) {
        //perform some tasks
    } else {
        //perform some other tasks
    }
}

为了正确地对上面的代码进行单元测试,我将 运行 至少进行两次单元测试。一个测试文件是否存在,另一个测试文件不存在时我的代码是否正确执行操作。因为单元测试,恕我直言,只测试我的代码而不进行集成测试,所以模拟 File 非常好,这样您就可以测试此方法的两个分支。

在集成测试期间,您可以使用真实文件进行测试,因为您的应用程序将与其周围环境进行交互。

试试 Mockito:

我不知道为什么 jmockit 不允许你模拟文件 class。在 Mockito 中它可以完成。示例如下。

import java.io.File;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class NewMain {    

    public static void main(String[] args) {
        File f = mock(File.class);
        when(f.exists()).thenReturn(true);
        System.out.println("f.exists = " + f.exists());
    }

}