【问题标题】:Are unit tests useful for real? [duplicate]单元测试真的有用吗? [复制]
【发布时间】:2011-11-23 12:31:21
【问题描述】:

可能重复:
Is Unit Testing worth the effort?

我知道一般来说单元测试的目的是什么,但我发现了一些困扰我的事情。

1) 测试早期错误发现的目的。因此,在后来的一些迭代中,如果我对代码进行了一些更改,自动化测试必须提醒我并告诉我我已经搞砸了我的软件很久以前被遗忘的部分。

但是,假设我有 A 类,并说它与其他一些类的实例交互,称之为 B 类。

当一个人为 A 类编写单元测试时,他必须模拟 B 类。 所以,在未来的某个时候,如果对 B 类进行一些更改,并导致一些错误,它们将只反映在 B 类的单元测试中,而不是 A 的(因为 A 的测试不使用真正的 B 类,但它是模拟的具有固定的输入和输出)。 所以,我看不出单元测试如何提前通知人们不知道的错误?我知道我正在更改的类中可能存在的错误,我不需要对其进行单元测试,我需要测试以提醒我我的更改的后果会导致某些“被遗忘”类中的错误,而这不是可以通过单元测试。还是我错了?

2) 在编写调用方法、它们的输入和返回值的模拟和正确期望时,必须知道被测类将如何实现。 我认为这与测试驱动开发相矛盾。在 TDD 中,首先编写测试,然后在它们的驱动下编写代码。 但是除非我编写必须测试的代码,否则我无法编写正确的期望(和一般的测试)。这与 TDD 相矛盾,对吧?

如果我使用真实对象而不是模拟对象,这两个问题都可以解决。但这不是单元测试,对吧?在单元测试中,被测类必须与系统的其余部分隔离,而不是使用真实的类,而是使用模拟。

我确定我在某个地方错了,但我找不到在哪里。我一直在阅读和阅读,我找不到我理解错误的地方。

【问题讨论】:

标签: unit-testing testing


【解决方案1】:

我刚刚第一次实现了 TDD 和单元测试。我认为它很棒,而且我从未在连续集成环境中使用它,我认为它更有价值。

我的过程:

  1. 创建业务逻辑所在的类骨架(无论是 服务层或域对象等)。
  2. 编写测试,并定义 测试中的方法名称和所需的功能 - 然后提示我 ide 编写 skelton 方法(一个小但不错的优点)
  3. 然后编写被测试的实际类方法。
  4. 运行测试、调试。

如果不先编写测试,我现在不能再编写代码了,它确实有助于开发。您可以立即发现错误,它确实可以帮助您以结构化的简单方式在精神上对代码和开发进行排序。当然,任何破坏现有功能的代码都会被立即捕获。

我还不需要使用模拟对象(使用spring我可以直接调用服务层和控制器方法)。

【讨论】:

    【解决方案2】:

    严格来说,您将更多时间花在编写单元测试上,而不是专注于实际代码。

    没有办法实现 100% 的代码覆盖率。我对我的应用程序进行单元测试,但我觉得它不值得。但并非所有人都同意。

    如果您更改一段代码,您的单元测试会失败并找出失败的原因,但对我来说这不值得。

    我不是单元测试的忠实拥护者......你模拟一切,但模拟是一项艰巨的任务............

    但现在公司正在尝试 TDD 方法。

    【讨论】:

    • 是的,“如果您更改一段代码,您的单元测试将失败并找出它失败的原因”,但是如果您模拟所有内容,当我更改某些方法时,只有该方法的测试可能会失败并且没有其他的。我说的是单元测试,而不是一般的测试。如果我嘲笑一切,那么一个班级的变化不会对其他班级的测试产生影响。如果我不模拟所有内容,那么据我所知,那不是单元测试。
    • @sadClown 这不是模拟对象的想法,afaik。模拟对象用于表示,例如 http 请求。您不测试模拟对象,它们在您的测试中使用并传递给您正在测试的代码。
    【解决方案3】:

    简单的答案:是的,它们对现实有用。

    TDD 在理论上很好,但我几乎从未见过它在实践中完成。但是,单元测试不受 tdd 约束。您始终可以为代码编写单元测试,以确保它在更改后仍然有效。单元测试的这种用法为我节省了无数小时的错误修复,因为测试立即指出了问题所在。

    我倾向于避免嘲笑。在大多数情况下,我认为它们不值得。不使用模拟可能会使我的单元测试更像是集成测试,但它可以完成工作。为确保您的课程按设计工作。

    【讨论】:

    • 您在代码中使用什么方法来模拟对象?你有什么简单的模拟魔法来模拟对象吗?或者你的代码中根本不使用对象?
    【解决方案4】:

    单元测试本身并不愚蠢,这取决于你的项目。

    我认为单元测试很好,不仅在 TDD 开发中,而且在任何类型的项目中。对我来说真正的优点是,如果您使用单元测试将关键代码包装在项目中,那么有一种方法可以知道您的意思是否仍然有效。

    对我来说,真正的问题是,如果有人弄乱了您的代码,他/她应该有办法知道测试是否仍然成功,而不是让它们手动运行。例如,让我们以 Eclipse + Java + Maven 为例。如果您在 Maven Java 项目上使用单元测试,那么每次有人构建它时,测试都会自动运行。所以,如果有人弄乱了你的代码,下次他构建它时,他会得到一个“BUILD FAILED”控制台错误,指出一些单元测试失败了。

    所以我的观点是:单元测试很好,但人们应该知道,每次更改代码时,如果不运行测试,他们就会把事情搞砸。

    【讨论】:

      【解决方案5】:

      0) 不,它没有。听起来很愚蠢,我的意思是。这是一个完全有效的问题。

      可悲的事实是,我们的行业充满了灵丹妙药和油腻腻的蛇油,如果某些事情没有意义,那么您提出质疑是对的。任何技术,任何工程任何部分的方法都只适用于某些情况。这些通常充其量都没有得到很好的记录,因此这一切都趋于恶化为完全没有意义的我的方法比你的方法更好的论点。

      我在单元测试方面取得了成功和失败,根据我的经验,如果正确应用它确实会非常有用。

      当您进行大量从头开始的开发工作时,这不是一个好的技术,因为一切都变化得太快,单元测试跟不上。在维护阶段,这是一项出色的技术,因为您正在更改一个更大的整体的一小部分,而这仍然需要按照应有的方式工作。

      对我来说,单元测试不是关于测试驱动的开发,而是按合同设计:单元测试检查接口是否被违反。从这里很容易看出,同一个人不应该编写一个单元及其相应的单元测试,所以对于非常小规模的东西,比如我自己的宠物项目,我从不使用它。在较大的项目中,我提倡使用它——但前提是采用按合同设计并且项目将接口规范视为重要的人工制品。

      单元测试作为一种技术也对单元大小很敏感。一个类不一定是可单独测试的,根据我的经验,该类通常太小而无法进行单元测试。你不想测试一个类本身,你想测试一个功能单元。可单独部署(可安装)的二进制文件,例如 jar 或 DLL,在我的书中是更好的候选者,或者如果您使用 Java 风格的语言,则为包。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-29
        • 2010-09-22
        • 2011-01-31
        • 2019-03-10
        • 1970-01-01
        • 2011-02-11
        • 2010-10-22
        • 1970-01-01
        相关资源
        最近更新 更多