如果我可以使用集成测试,为什么还要打扰单元测试呢?

时间:2010-04-09 17:59:44

标签: unit-testing

好的,我知道我正在做出这样的陈述,所以我的问题是每个人都说服我,我错了。采取这种情况:

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

所以我单元测试B,结果为null。所以我测试返回null,并且单元测试通过。好的。

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

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

为什么我错了?

12 个答案:

答案 0 :(得分:23)

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

一旦我们只是将单元测试与功能测试进行比较,我就不会提到整体测试的好处:

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

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

答案 1 :(得分:10)

单元测试不是用于测试集成中应测试的内容 - 它们是互补的测试集。单元测试可以保证给定的单元代码本身可以执行它的设计,而不是其他任何东西。集成测试可确保所有单元能够很好地协同工作,以执行总体要求。

答案 2 :(得分:5)

单元测试更细粒度,允许您查明错误。如果A或B失败怎么办?如果集成测试失败,您怎么知道哪一个失败了?这只是两种方法 - 想象一下,如果你是集成测试Web应用程序的前端控制器,它会加载一些模型并调用一堆方法。这将是一场噩梦,试图找出究竟出了什么问题。

答案 3 :(得分:5)

我认为主要原因是:

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

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

答案 4 :(得分:4)

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

但是假设你有一个方法必须返回一个介于1和9之间的值,你为它编写一个测试并发现它返回一个null或10的值,然后你知道代码在你进入集成之前很久就被破坏了测试

答案 5 :(得分:4)

我同意你的看法,在你的简单案例中,不需要进行单元测试。测试(单元,集成,功能,回归)都取决于项目的规模,涉及的人数以及所涉及的每个人的经验水平。

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

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

我还相信,由于您有多个人在很长一段时间内从事该项目(阅读除了丢弃项目以外的任何内容),您还需要进行自动化集成测试,以确保各个组件协同工作。 / p>

答案 6 :(得分:3)

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

在最初的开发过程中说单元测试是浪费时间,就像抱怨我的车在驶出车道的路上行驶时一样蹩脚。

答案 7 :(得分:3)

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

答案 8 :(得分:2)

我没有看到其他人发言的另一个原因是:你不会总是那个维护你写的代码的人。我们假设我已经写过A& B在单独的模块中,因此每个模块都在一个单独的罐子里。有自己的maven构建文件。让我们进一步假设A是Dao方法,B是某种服务层。如果我为Dao写了一个基本的单元测试(也许是使用测试驱动的开发,甚至!),我对将来对数据库结构的更改有了更多的信心。可能影响我的dao的查询被提前发现。例如,如果在我的团队中,另一个开发人员需要将列添加到我的dao使用的数据库表中,我当然希望他们立即知道如果这样做会破坏我的dao方法。如果他们不得不等待构建所有图层和在我看来,运行集成测试来验证它们只是浪费了宝贵的开发时间。作为一名开发人员,我宁愿进行10次单位测试10次以修复&测试我发现的任何休息,而不是运行2分钟的集成构建&集成测试运行多次。显然,时间根据项目(和你的硬件)的大小而变化很大,但这些是我在当前项目中处理的那种时候。

答案 9 :(得分:2)

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


选择时: 1)单元测试和小型集成测试 VS 2)只是集成测试 你正在计算赌注。如果集成组件很复杂,那么集成测试中的任何失败都很难找到没有单元测试的情况。有时候我弄错了,在集成测试中遇到测试失败并开始编写单元测试而不尝试调试。 如果你打赌不需要单元测试并获胜,你可以节省相当多的时间,并且仍然对你的代码有信心,但是你没有得到单元测试为下一个拥有的人带来的“规范”好处触摸你的代码。

答案 10 :(得分:1)

大多数问题出现在您提出的方案中 - 根据您的描述,所有 B确实返回null。单元测试一些微不足道的东西可能是毫无意义的 - 但是正在编写代码来开始。如果您只需要null,则直接使用null并完全消除B.如果B通过真正做的事情来证明它的存在而不是返回null,那么你所描述的单元测试是不完整的,你需要测试B应该做的其他事情。

答案 11 :(得分:0)

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