【问题标题】:Why should I bother with unit testing if I can just use integration tests?如果我只能使用集成测试,我为什么还要费心进行单元测试?
【发布时间】:2010-04-09 17:59:43
【问题描述】:

好的,我知道我会做出这样的声明,所以我的问题是让每个人都说服我我错了。以这种情况为例:

我有方法A,它调用方法B,它们在不同的层。

所以我对 B 进行了单元测试,结果为 null。所以我测试返回null,单元测试通过。不错。

然后我对 A 进行单元测试,它期望从 B 返回一个空字符串。所以我模拟 B 层所在的层,返回一个空字符串,测试通过。又好看了(假设我没有意识到 A 和 B 的关系,或者可能是两个不同的人正在构建这些方法)

我担心的是,直到我们一起测试 A 和 B,即集成测试,我们才能找到真正的问题。由于集成测试提供了对单元测试区域的覆盖,因此构建所有这些实际上并没有告诉我们任何(或非常)有意义的单元测试似乎是一种浪费。

为什么我错了?

【问题讨论】:

  • @Finglas 我更改了他帖子的标题以更准确地反映他的要求。在这种情况下,它不是骗子。
  • 单元测试适用于没有真正的最后期限、管理不善的日程安排、项目后期引入新要求、更改/故障硬件等...以及有时间去做的人一些东西,比如单元测试。在现实世界中这是不存在的……你的老板永远不会给你时间去做这件事,因为很难从数量上证明它的合理性。
  • @reinier 什么?任何具有管理计划的项目都应该为单元测试留出特定的时间。构建有自己的截止日期,单元测试有另一个截止日期。如果你的公司没有给你时间来测试你创造的东西,那就找一家新公司。
  • @reinier - 你的老板可能不会给你时间进行单元测试,这并不意味着没有老板了解它的重要性。很抱歉您在这样的环境中工作。
  • 有时我希望我能对愚蠢的 cmets 投反对票。

标签: unit-testing


【解决方案1】:

这里是 an article on test categorization 带有一些参数

我不会提到整体测试的好处,我们只是比较单元测试和功能测试:

  • 单元测试可帮助您缩小出现错误时查看的范围。 - 我们在此场景中包含 C、D、E、...、Z 类。 如果你只有集成测试但它失败了,你从哪里开始寻找?如果你没有单元测试,你需要在每个类和“接线”中到处查看" 之间的 (这是一个更窄的范围)。如果你有单元测试,那么你只需要检查接线。在这种情况下,没有一些较小的集成测试也是一件坏事,比如只测试 A、B、C 和 D(所以你已经知道它们之间的“连线”是否真的有效)。
  • 使用单元测试,您会更快地失败。如果您使用 TDD,则更是如此。您可能在创建所有 A 类和 B 类之后编写测试。当您运行测试时,A 和 B 的工作方式在您的脑海中并不新鲜(也许您是在前一周编写的 - 希望您不要开始测试仅当产品“完成”时)。然后你必须记住你写这些的时候在想什么。此外,单元测试速度更快,因此您更有可能更频繁地运行它们(也许每次保存时都会自动运行它们?)
  • 单元测试可以更好地记录您的类的行为方式。如果您是“普通程序员”,您可能讨厌编写文档。这会迫使您在编程时编写文档,并强制文档永不过时(如果是,您的测试将失败)。而且当您需要更改其他人的代码时,它也会有所帮助

理想的世界中,当测试失败时,您不需要超过 2 分钟就可以知道要查看的内容(无需调试)。进行各种规模的测试的想法只是实现这一目标的指导方针,而不是花费数小时/数天/数周进行调试 =)。

【讨论】:

  • 因此,您无需花几个小时进行调试,而是花费数天时间构思每一个可能失败或可能不会失败的测试。除此之外,很多东西都不容易测试。像网络数据和gui。我知道单元测试是你刚从学校毕业的时候做的时髦的事情。但正如我在之前的评论中所说,有时最好利用这段时间来提高工作效率;^)
  • 但是使用调试器,我可以浏览方法以查看失败的位置。假设我需要忽略调试器似乎很理想化。
  • 我不反对调试。有时需要它。但是为代码中的每个方法创建一个单元测试(其中 99.9% 永远不会失败)以便为您节省 5 分钟的调试时间,这简直是愚蠢的。似乎很多人都害怕调试。使用当前的工具,没有什么比这更容易了。
  • 这就像一个关于在一个街区外丢了钥匙的人的老笑话,但他正在寻找这里,因为光线更好。集成是事情破裂的地方。当测试驱动开发基于集成测试而不是单元测试时,它会更有意义。
  • @CodeGrue 理想情况下您不需要调试器(并非总是如此)
【解决方案2】:

单元测试不是为了测试应该在集成中测试的内容——它们是互补的测试集。单元测试保证给定的 unit 代码自己执行它的设计目的,没有别的。集成测试确保您的所有单元能够很好地协同工作以执行总体要求。

【讨论】:

  • +1 如果您的集成测试示例通过,那么您永远不会知道 A 或 B 都没有达到预期结果。
  • 我的论点是集成测试也能捕捉到单元的功能。
  • @CodeGrue - 它可能会也可能不会。无论如何,如果您在单元测试中看不到任何价值,那就别管它了。如果它有效,那就太好了。没有人说单元测试是必需来使系统工作,只是它们可能会给你一个更好的机会来实现它。
【解决方案3】:

单元测试的粒度更细,可让您查明错误。如果 A 或 B 失败了怎么办?如果你的集成测试失败了,你怎么知道哪一个失败了?这只是 2 种方法——想象一下,如果您正在集成测试 Web 应用程序的前端控制器,它会加载少量模型并调用一堆方法。试图追查到底出了什么问题,那将是一场噩梦。

【讨论】:

  • 再次,我可以在调试器中检查所有这些以查看导致失败的原因。另一种方法是模拟“大量模型”,希望我已经涵盖了所有场景。
  • 我开始有同样的想法。我宁愿检查调试器,而不是嘲笑“大量模型”。所以对我来说,单元测试没有明显的好处。如果某些东西要进行单元测试,它应该可以在没有模拟的情况下进行测试。类似于基础设施服务或公用事业服务。
【解决方案4】:

我认为主要原因是:

1:单元级测试为您提供有关失败原因的更多信息。

2:在您的组件被集成之前,您无法运行集成测试。越早发现错误,修复就越容易/更便宜。

【讨论】:

    【解决方案5】:

    好的,单元测试不会发现所有问题,这也是我们进行集成测试的原因!

    但是假设您有一个必须返回 1 到 9 之间的值的方法,并且您为它编写了一个测试并发现它返回了一个 null 或 10 的值,那么您在进行集成之前很久就知道代码已损坏测试。

    【讨论】:

    • 我猜这对于不需要数据的方法来说很好。在我的应用程序中,只有不到 1% 的方法是纯逻辑的,其余的都是操作数据。所以我的测试中有 1% 是单元测试...
    【解决方案6】:

    我同意你的观点,在你的简单情况下,不需要单元测试。测试(单元、集成、功能、回归)都取决于项目的规模、参与的人数以及参与的每个人的经验水平。

    随着这些因素中的任何一个增加(嗯,最后一个必须减少),测试的需求就会增加。您需要找到适合并适用于您的特定项目的解决方案。

    我是单元测试的忠实拥护者,我相信所有开发人员都应该编写并自动化它们,无论项目的规模如何。他们将确保您的代码没有错误,并且在您几个月后返回项目时会真正提供帮助。

    我还认为,由于您有多个人在很长一段时间内从事该项目(阅读除一次性项目之外的任何内容),因此您还需要自动化集成测试以确保各个组件协同工作。

    【讨论】:

      【解决方案7】:

      集成测试受到combinatorial explosion 的影响:假设方法 A 有 5 种不同的行为方式(不同的边缘情况等),方法 B 也是如此。如果将它们一起测试,现在理论上有 25 种不同的情况你必须测试!是的,它们中的许多最终可能是相同的,或者由于某种原因不能发生,但基本上,你一起测试的东西越多,就越不可能测试所有的边缘情况。

      【讨论】:

        【解决方案8】:

        单元测试与初始开发期间的调试无关。它们是关于设计的,它们是关于适应变化的。当我第一次通过大量代码时,我的单元测试几乎从不告诉我错误在哪里。当六个月后出现错误时,我的测试会警告我,因为有人(可能是我自己)调整了他们不完全了解的关系的对象。

        说单元测试在最初的开发过程中是浪费时间,就像抱怨我的车在驶出车道时行驶里程很差。

        【讨论】:

          【解决方案9】:

          另一个我没有看到其他人解决的原因:你不会总是维护你编写的代码。假设我已经在单独的模块中编写了 A 和 B,所以每个都在一个单独的 jar 中,并且有自己的 Maven 构建文件。让我们进一步假设 A 是一个 Dao 方法,而 B 是某种 Service 层。如果我为我的 Dao 编写了一个基本的单元测试(甚至可能使用测试驱动开发!),我更有信心在未来对可能影响我的 dao 的数据库结构和查询的更改会尽早发现。例如,如果在我的团队中,另一个开发人员需要向我的 dao 使用的数据库表中添加列,我当然希望他们立即知道这样做是否会破坏我的 dao 方法。如果他们必须等待构建所有层并运行集成测试来验证这一点,在我看来,他们只是在浪费宝贵的开发时间。作为开发人员,我宁愿运行 10 秒的单元测试 10 次来修复和测试我发现的任何中断,而不是运行 2 分钟的集成构建和集成测试运行多次。显然,时间根据项目(和您的硬件)的大小而有很大差异,但这些是我在当前项目中处理的时间。

          【讨论】:

            【解决方案10】:

            加强(希望)Samuel Carrijo 的帖子...


            选择时: 1)单元测试和一个小的集成测试 对比 2)只是集成测试 您正在进行有计划的赌注。如果集成组件很复杂,那么在没有单元测试的情况下,集成测试中的任何故障都很难找出来。有时我弄错了,在集成测试中测试失败并开始编写单元测试而不尝试调试。 如果您打赌不需要单元测试并获胜,您可以为自己节省大量时间,并且仍然对您的代码充满信心,但您不会获得单元测试为下一个拥有的人提供的“规范”好处触摸您的代码。

            【讨论】:

              【解决方案11】:

              大部分问题出在您所假设的场景中——根据您的描述,所有 B 所做的是返回 null。对一些微不足道的东西进行单元测试可能是毫无意义的——但它是从编写代码开始的。如果你只需要一个null,直接使用null并完全消除B。如果 B 通过实际做的不仅仅是返回 null 来证明它的存在,那么你描述的单元测试是不完整的,你需要测试 B 应该做的任何其他事情。

              【讨论】:

              • 假设 B 做了很多工作来确定 null 是正确的响应。
              • @CodeGrue:在这种情况下,您需要在完成大量工作时对其进行正确测试。
              【解决方案12】:

              如果 A 是一个运行 2 小时的查询,并为 B 准备数据,这是另一个运行 2 小时的查询,我可以等待 2 个小时,为什么还要等待 4 个小时才能找到问题?这不像是一个新想法。您认为汽车公司会在查看发动机是否工作之前组装整辆汽车吗?

              【讨论】:

              • 但是在我的场景中,你会测试2小时,然后再测试2小时,然后再测试4小时才发现有问题。
              • 通过单元测试,您运行模块 A(2 小时),修复问题,重新运行模块 A(2 小时),运行模块 B(2 小时),组装,运行整个事情(4 小时) )。所以你总共有 10 个小时,而没有单元测试的时间是 8 个小时。所以单元测试几乎不会增加那么多时间。但我选择的 2 小时并没有什么神奇之处。 B 越长越好。
              • 更不用说您将零时间分配给解决问题。几乎可以肯定,解决单元测试中发现的问题所花费的时间比集成测试中发现的问题要少。
              • 非常真实的大卫。另外,这 2 小时的时间差很可能只是试图找出哪个模块实际上失败了。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-09-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多