[讨论] 在业务系统中写了 e2e 测试,还需要写单元测试吗?

2020-01-15 15:44:51 +08:00
 PixelMage

假设你现在实现了一个登录注册的系统

你写 e2e 测试用例把你的所有的 http 接口的功能以及异常情况都测了一遍并通过

这时候还需要写单元测试吗?

如果用?为什么? 如果不用,那是否以后业务系统就只需要写 e2e 测试就好了?

2472 次点击
所在节点    程序员
19 条回复
lihongjie0209
2020-01-15 17:36:49 +08:00
你测试了 HTTP 接口就不需要测试 StringUtil 了? 单元测试测试的具体的代码, HTTP 接口测试的是具体的业务
index90
2020-01-15 18:49:16 +08:00
如果你能确保你的接口测试用例,能够覆盖代码中所有可能的条件分支,那当然是最好的了。
然而现实问题是,编写有效的接口测试比编写有效的单元测试成本更高。
我这边的做法是,开发编写单元测试,覆盖 99%的代码行。QA 做功能测试,优先覆盖开心路径,逐步补齐异常测试用例。这样兼顾开发效率和软件质量。
lihongjie0209
2020-01-15 22:32:19 +08:00
@index90 #2 99%的单测覆盖率, 可以具体说一下吗
kwrush
2020-01-16 06:48:56 +08:00
e2e 把所有分支和情况都 cover 了,那可比单元测试难度高多了,我觉得根本就不可能,何必自寻死路。
PixelMage
2020-01-16 09:22:13 +08:00
@lihongjie0209 其实我想表达的意思是,如果所有的业务情况,以及业务能考虑到的异常情况都通过了测试。为什么还需要考虑代码的单测?毕竟 it works?
这只是我片面的想法哈,因为我觉得既然 e2e 都写好了,业务都 OK 了,我又何必在乎具体的代码。
还请多指教~
PixelMage
2020-01-16 09:23:15 +08:00
@kwrush 可能是我写的系统的比较简单,最多也就十来张表,CRUD,所以都是直接写 E2E 不写单测,最近产生了这个疑惑——“为什么还要写单测”
PixelMage
2020-01-16 09:24:44 +08:00
@index90 学习了,感谢回复。可能是我现在的系统比较简单的缘故,我直接写 E2E 更快~
lolizeppelin
2020-01-16 10:04:01 +08:00
写单元测试的过程就是优化和重构代码的过程

写接口测试做不到
index90
2020-01-16 10:38:14 +08:00
@lihongjie0209 #3
1. 每开发一个特性,就从主干拉出特性分支
2. 开发完并加上单元测试,就提 MR
3. MR 触发流水线,跑单元测试,计算代码行覆盖率,不达标就不通过
4. 流水线跑通过后,才能合并回主干

PS:关于特性,这里不是产品特性,更多是研发角度的特性,例如加个函数,加一个类等。我们一般趋向于把产品特性切分成多个更细的开发特性,这样可以确保分支不会离开主干太久。
PPS:关于单元测试的有效性,执行层面上,只有代码覆盖率这一个可量化指标,而单元测试有效性只能靠自觉了( assert 的编写其实很影响单元测试的有效性的),例如一旦被发现“作弊”,就会被开除。

不知道这是不是你想问的……
index90
2020-01-16 10:41:31 +08:00
@lolizeppelin #8
对,写久了单元测试,就会有这样的感觉:
如果发现单元测试比较难写,就会考虑我的代码设计是不是有问题
lihongjie0209
2020-01-16 10:44:57 +08:00
@index90 #9 感谢回复, 我比较好奇你们的 service 层和 dao 层是做单元测试的.
index90
2020-01-16 11:23:04 +08:00
@lihongjie0209 凡是人手写的代码都需要写单元测试,只要是个函数都可以写单元测试。实践过程里可能比较棘手的是如何 mock 了。刚开始的时候挺痛苦的,现在基本不会出现无法写单元测试的情况(除了要往老代码里加特性)。
PixelMage
2020-01-16 12:26:38 +08:00
@index90 想请教一下
在 e2e 测试覆盖了所有业务逻辑的情况下,
出于对业务系统稳定性的考虑,而不是代码逻辑优化的考虑下,
是否还有必要再写单测?
index90
2020-01-16 13:29:44 +08:00
@PixelMage 你这句话从理论上说没错,但实际上,你要 e2e 测试覆盖所有业务逻辑几乎不可能。

而且服务程序还要考虑 failure 的情况吧,例如下游服务无响应,响应超时,例如数据库连接失败,查询失败等情况。如果要在 e2e 测试中完成,你还要部署这样的环境出来,而用单元测试的话就可以轻松覆盖这些异常情况了。

回到你的问题:
“在 e2e 测试覆盖了所有业务逻辑的情况下,” ——业务逻辑覆盖是否有可量化指标,如何证明你覆盖了“所有”的业务逻辑呢?
“出于对业务系统稳定性的考虑,而不是代码逻辑优化的考虑下,”——系统稳定并不只有业务逻辑,还有其他异常情况考虑
“是否还有必要再写单测?”——单元测试只是一种软件质量保证的手段,而且经过多年的考验,看看那些著名的开源软件有没有写单元测试。如果你觉得你比那些牛人聪明,你有比单元测试更好的手段去保障软件质量,你可以选择你的方法。
PixelMage
2020-01-16 14:24:27 +08:00
@index90 感谢你的回答,真的,我困扰了很久。

确实如果你所说,我并没有考虑到下游没响应,数据库失败的情况,我只覆盖了业务的正常流和异常流。但我很好奇如何在单测里覆盖这些东西?不知道有没有 repo 可以参考一下(我是真的想学习一下,没有别的意思)

“业务逻辑覆盖是否有可量化指标,如何证明你覆盖了“所有”的业务逻辑呢” ——也只能尽量,毕竟总有黑天鹅,尽量的意思就是 1. 梳理出所有可能的业务异常情况并测试到 2. 测试覆盖率

“系统稳定并不只有业务逻辑,还有其他异常情况考虑”, “单元测试只是一种软件质量保证的手段,而且经过多年的考验
....你可以选择你的方法”——
没错你说得对,但是在日常的业务系统开发中,而不是伟大软件开发中,经常会出现为了开发速度牺牲质量的 tradeoff,我其实很倾向于“只写 e2e 是一种比较划算的 tradeoff”。另:我问一个我在阿里写 java 的同事这个问题,他说:哪有时间写什么测试,直接丢给测试同学。所以我觉得这种现象是常见的。理想情况下,当然是都写最好,但是现实世界往往不尽如人意。

再一次感谢你的回答~真的很认真,感谢。
index90
2020-01-16 17:17:25 +08:00
@PixelMage 要找 repo 的话,可以上 github 上找,我看得比较多是 dgraph 和 k8s 的 repo (跟工作有关)。
哦对了,我是 Gopher,Java 不是很熟,不过根据经验,标准库里面的例子就足够学了,我相信 Java 的标准库应该也有单元测试的。

关于你最后一点“但是在日常的业务系统开发中,而不是伟大软件开发中,经常会出现为了开发速度牺牲质量的 tradeoff”,我想还是分享一下我的经历。(这里的质量,我理解的是程序是否有 bug,而不是代码优不优雅的问题)

其实刚开始我们也是觉得写单元测试浪费时间,如果把开发活动框在从研发到打包这段过程的话,单元测试的确是影响了开发进度的。但是如果你把软件的发布,运营,bug 反馈,定位,修复,再发布这些环节考虑进来,你会崩溃掉的。

“为了开发速度牺牲质量”,其实到了最后我们发现这是个伪命题来的,因为软件质量是第一位的。如果软件万一真的有 bug,即使不考虑业务损失,当这个 bug 出现的时候,你需要马上放下手上正在开发的特性,去排查定位,重建环境,代码修复,测试,打包,发布等,这一系列的工作牵扯到的不只是写出这个 bug 的那一位研发人员,而是牵扯到运维,测试等一系列人员。将人力成本,时间成本,沟通成本等考虑进来之后,其实整个团队的研发效能非常低的。

当然,如果一个研发人员和一个测试人员合作无间,测试能够在出现 bug 的时候,就直接告诉研发人员是哪个模块甚至哪一行出问题了,这种分工也是没问题的,但是我没见过。语言沟通有效率本来就够低了,更何况现在研发和测试都不在一个办公室里,用 IM 发着文字沟通,又或者在看板上发评论来沟通 bug。

“为了开发速度牺牲质量”这种观念很普遍,我猜是因为大部分研发人员都是个体在工作,容易把自己的职责框在写代码到代码提交之间。但当你开始关心整个研发团队的效能上时,你很容易发现问题。
PixelMage
2020-01-16 17:43:39 +08:00
@index90

对于“业务系统是否应该写测试”,我觉得我们都是一致的,不写测试带来的都是短期的时间收益,和长期的整体研发效能损失。所以对于“为了开发速度牺牲质量——不写测试”,我也是觉得不可取的。

但是我更想知道的是“ [业务] 系统里只写 E2E 不写单元来达到时间和收益的最佳 tradeoff”是不是合适的?
我举一个量化的例子
我假设写 E2E 测试能 COVER 90%的业务 BUG,需要花费 1 个单位的时间
如果我再补上单元测试,能再补上 9.9%的业务 BUG,但是需要额外花费 1 个单元的时间

那么此时我认为,只写 E2E,不写单元是比较划算的。
这里有两个问题
1. E2E 测试能不能 COVER 90%的业务问题?
2. E2E 测试环境的搭建是否真的比单元测试简单?

其中
1.我觉得对于中小系统都是适用的,写完正常流和异常流的 E2E,我认为能够覆盖 80 90 的问题。
2. E2E 的测试环境,如今在各种中大型开发团队,比如阿里,都是日常、预发、线上,三套或以上环境 ,天然就有公司准备好的环境,不需要你再去搭建什么,所有的系统都遵守了这个规则,所以在中大型团队,我认为这个没什么成本。在小型团队,那可能写不写测试都是问题了。

综合来说,我想说的观点,一句话就是
“在大部分非核心中小型系统里,只写 E2E 测试是权衡了效率和质量的好选择”
index90
2020-01-16 18:08:24 +08:00
@PixelMage sorry,我看了前半句没看后半句,误解了你的意思。

感觉我们的讨论有点跑偏,e2e 测试和单元测试其实是处在不同维度,解决的具体问题是不一样的,不能用来直接比较,不是一个非零即一的问题。

单元测试是验证代码逻辑问题,而不是验证业务逻辑问题。
相反,e2e 测试只能保证业务逻辑正确,但无法保证代码或软件是健壮的。(或者需要很大代价)
PixelMage
2020-01-16 18:48:09 +08:00
@index90
我个人的粗浅理解是,一些核心基础中间件之类的,单测,E2E 我觉得都不能少。
但是如果是一个业务系统的话,这可能就回到我提出的这个问题了~

其实我个人的小心思是:既然业务 e2e 测已经 work 了,异常流也 cover 到了,单测带来的代码健壮提升 i don't care,毕竟后面还有 IDE,语言框架,lint, 代码风格检查,开发规约拉着我。

这样可以提高业务的落地速度,但是要是说后续的可维护可扩展性的,写单测应该是会有提高的,但是提高多大,就不太好说了,估计每个业务系统可能都不一样。

还是特别感谢你的回复,我收获了不少东西~~对单测的看法也没有那么片面了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/638157

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX