【问题标题】:Why should I not be mocking File or Path为什么我不应该嘲笑文件或路径
【发布时间】:2016-12-23 22:24:32
【问题描述】:

我一直在努力理解 jmockit Mocking API 支持的类的雷区。我发现我认为是 File 的错误,但问题只是简单地关闭了说“不要模拟文件或路径”,没有任何解释。这里有人可以帮助我理解为什么不应该嘲笑某些课程以及我应该如何解决这个问题。我正在尝试通过错误报告为库做出贡献,但我提交的每个文件都让我更加困惑。请原谅我的无知,但如果有人能指出禁止模拟等的理由,我将不胜感激。

【问题讨论】:

    标签: java unit-testing jmockit


    【解决方案1】:

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

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

    话虽如此,我会尝试一下。

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

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

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

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

    您不应该在 JVM 中模拟类。

    您特别询问了有关文件或流的原因 - 这是一个。接受它或忽略它。

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

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

    【讨论】:

    • 我仍然不明白为什么我不能模拟 File 对象。我应该只注入字符串和流,而不是直接注入文件或路径吗?当然,我也必须说服我团队中的所有其他开发人员。
    • 模拟文件到底意味着什么?你为什么对它如此执着?如果您团队中的每个人都告诉您这不是一个好主意,您为什么如此执着于它?我已经给了你一个有意义的例子——服务——它不是字符串或流。无论如何都要这样做。如果它对你有用,那就太好了。如果没有,请承认这是浪费时间并继续前进。
    • 我想你误会了,我会说服团队中的其他成员不要模拟文件。我非常关注它,因为我团队的其他成员将一个文件注入到一个类中。这意味着需要模拟对 getAbsolutePath 的调用。
    • 文件是外部资源。您可能会说它与数据库没有什么不同。它有一个与 getAbsolutePath、getRealPath、exists 等调用的接口。对于需要文件依赖项的单元测试,我需要能够模拟这些响应,因为此时不存在真实文件。它与数据库相同。
    • 我认为我在测试数据访问对象时不会模拟数据库连接。正如我所说的那样,我不会模拟文件。为何如此执着?软件开发是一项社交团队运动。过于教条并坚持正确的人可能会疏远队友。此外,是什么阻止了你?去做吧。看看嘲笑是否适合你。如果是这样,请继续这样做。如果没有,就让它过去吧。
    【解决方案2】:

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

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

    例如:

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

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

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

    试试 Mockito:

    我不知道为什么 jmockit 不允许你模拟 File 类。在 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());
        }
    
    }
    

    【讨论】:

    • 我是这么想的,但是 jmockit 不再支持它。或者至少认为不值得修复周围的错误。
    猜你喜欢
    • 2013-02-16
    • 2010-09-07
    • 1970-01-01
    • 2023-02-08
    • 2012-07-26
    • 2011-02-09
    • 1970-01-01
    • 2021-11-19
    • 2019-09-08
    相关资源
    最近更新 更多