假设你现在实现了一个登录注册的系统
你写 e2e 测试用例把你的所有的 http 接口的功能以及异常情况都测了一遍并通过
这时候还需要写单元测试吗?
如果用?为什么? 如果不用,那是否以后业务系统就只需要写 e2e 测试就好了?
1
lihongjie0209 2020-01-15 17:36:49 +08:00 1
你测试了 HTTP 接口就不需要测试 StringUtil 了? 单元测试测试的具体的代码, HTTP 接口测试的是具体的业务
|
2
index90 2020-01-15 18:49:16 +08:00 1
如果你能确保你的接口测试用例,能够覆盖代码中所有可能的条件分支,那当然是最好的了。
然而现实问题是,编写有效的接口测试比编写有效的单元测试成本更高。 我这边的做法是,开发编写单元测试,覆盖 99%的代码行。QA 做功能测试,优先覆盖开心路径,逐步补齐异常测试用例。这样兼顾开发效率和软件质量。 |
3
lihongjie0209 2020-01-15 22:32:19 +08:00
@index90 #2 99%的单测覆盖率, 可以具体说一下吗
|
4
kwrush 2020-01-16 06:48:56 +08:00 1
e2e 把所有分支和情况都 cover 了,那可比单元测试难度高多了,我觉得根本就不可能,何必自寻死路。
|
5
PixelMage OP @lihongjie0209 其实我想表达的意思是,如果所有的业务情况,以及业务能考虑到的异常情况都通过了测试。为什么还需要考虑代码的单测?毕竟 it works?
这只是我片面的想法哈,因为我觉得既然 e2e 都写好了,业务都 OK 了,我又何必在乎具体的代码。 还请多指教~ |
6
PixelMage OP @kwrush 可能是我写的系统的比较简单,最多也就十来张表,CRUD,所以都是直接写 E2E 不写单测,最近产生了这个疑惑——“为什么还要写单测”
|
8
lolizeppelin 2020-01-16 10:04:01 +08:00 via Android
写单元测试的过程就是优化和重构代码的过程
写接口测试做不到 |
9
index90 2020-01-16 10:38:14 +08:00
@lihongjie0209 #3
1. 每开发一个特性,就从主干拉出特性分支 2. 开发完并加上单元测试,就提 MR 3. MR 触发流水线,跑单元测试,计算代码行覆盖率,不达标就不通过 4. 流水线跑通过后,才能合并回主干 PS:关于特性,这里不是产品特性,更多是研发角度的特性,例如加个函数,加一个类等。我们一般趋向于把产品特性切分成多个更细的开发特性,这样可以确保分支不会离开主干太久。 PPS:关于单元测试的有效性,执行层面上,只有代码覆盖率这一个可量化指标,而单元测试有效性只能靠自觉了( assert 的编写其实很影响单元测试的有效性的),例如一旦被发现“作弊”,就会被开除。 不知道这是不是你想问的…… |
10
index90 2020-01-16 10:41:31 +08:00
|
11
lihongjie0209 2020-01-16 10:44:57 +08:00
@index90 #9 感谢回复, 我比较好奇你们的 service 层和 dao 层是做单元测试的.
|
12
index90 2020-01-16 11:23:04 +08:00
@lihongjie0209 凡是人手写的代码都需要写单元测试,只要是个函数都可以写单元测试。实践过程里可能比较棘手的是如何 mock 了。刚开始的时候挺痛苦的,现在基本不会出现无法写单元测试的情况(除了要往老代码里加特性)。
|
13
PixelMage OP |
14
index90 2020-01-16 13:29:44 +08:00 1
@PixelMage 你这句话从理论上说没错,但实际上,你要 e2e 测试覆盖所有业务逻辑几乎不可能。
而且服务程序还要考虑 failure 的情况吧,例如下游服务无响应,响应超时,例如数据库连接失败,查询失败等情况。如果要在 e2e 测试中完成,你还要部署这样的环境出来,而用单元测试的话就可以轻松覆盖这些异常情况了。 回到你的问题: “在 e2e 测试覆盖了所有业务逻辑的情况下,” ——业务逻辑覆盖是否有可量化指标,如何证明你覆盖了“所有”的业务逻辑呢? “出于对业务系统稳定性的考虑,而不是代码逻辑优化的考虑下,”——系统稳定并不只有业务逻辑,还有其他异常情况考虑 “是否还有必要再写单测?”——单元测试只是一种软件质量保证的手段,而且经过多年的考验,看看那些著名的开源软件有没有写单元测试。如果你觉得你比那些牛人聪明,你有比单元测试更好的手段去保障软件质量,你可以选择你的方法。 |
15
PixelMage OP @index90 感谢你的回答,真的,我困扰了很久。
确实如果你所说,我并没有考虑到下游没响应,数据库失败的情况,我只覆盖了业务的正常流和异常流。但我很好奇如何在单测里覆盖这些东西?不知道有没有 repo 可以参考一下(我是真的想学习一下,没有别的意思) “业务逻辑覆盖是否有可量化指标,如何证明你覆盖了“所有”的业务逻辑呢” ——也只能尽量,毕竟总有黑天鹅,尽量的意思就是 1. 梳理出所有可能的业务异常情况并测试到 2. 测试覆盖率 “系统稳定并不只有业务逻辑,还有其他异常情况考虑”, “单元测试只是一种软件质量保证的手段,而且经过多年的考验 ....你可以选择你的方法”—— 没错你说得对,但是在日常的业务系统开发中,而不是伟大软件开发中,经常会出现为了开发速度牺牲质量的 tradeoff,我其实很倾向于“只写 e2e 是一种比较划算的 tradeoff”。另:我问一个我在阿里写 java 的同事这个问题,他说:哪有时间写什么测试,直接丢给测试同学。所以我觉得这种现象是常见的。理想情况下,当然是都写最好,但是现实世界往往不尽如人意。 再一次感谢你的回答~真的很认真,感谢。 |
16
index90 2020-01-16 17:17:25 +08:00 1
@PixelMage 要找 repo 的话,可以上 github 上找,我看得比较多是 dgraph 和 k8s 的 repo (跟工作有关)。
哦对了,我是 Gopher,Java 不是很熟,不过根据经验,标准库里面的例子就足够学了,我相信 Java 的标准库应该也有单元测试的。 关于你最后一点“但是在日常的业务系统开发中,而不是伟大软件开发中,经常会出现为了开发速度牺牲质量的 tradeoff”,我想还是分享一下我的经历。(这里的质量,我理解的是程序是否有 bug,而不是代码优不优雅的问题) 其实刚开始我们也是觉得写单元测试浪费时间,如果把开发活动框在从研发到打包这段过程的话,单元测试的确是影响了开发进度的。但是如果你把软件的发布,运营,bug 反馈,定位,修复,再发布这些环节考虑进来,你会崩溃掉的。 “为了开发速度牺牲质量”,其实到了最后我们发现这是个伪命题来的,因为软件质量是第一位的。如果软件万一真的有 bug,即使不考虑业务损失,当这个 bug 出现的时候,你需要马上放下手上正在开发的特性,去排查定位,重建环境,代码修复,测试,打包,发布等,这一系列的工作牵扯到的不只是写出这个 bug 的那一位研发人员,而是牵扯到运维,测试等一系列人员。将人力成本,时间成本,沟通成本等考虑进来之后,其实整个团队的研发效能非常低的。 当然,如果一个研发人员和一个测试人员合作无间,测试能够在出现 bug 的时候,就直接告诉研发人员是哪个模块甚至哪一行出问题了,这种分工也是没问题的,但是我没见过。语言沟通有效率本来就够低了,更何况现在研发和测试都不在一个办公室里,用 IM 发着文字沟通,又或者在看板上发评论来沟通 bug。 “为了开发速度牺牲质量”这种观念很普遍,我猜是因为大部分研发人员都是个体在工作,容易把自己的职责框在写代码到代码提交之间。但当你开始关心整个研发团队的效能上时,你很容易发现问题。 |
17
PixelMage OP @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 测试是权衡了效率和质量的好选择” |
18
index90 2020-01-16 18:08:24 +08:00
@PixelMage sorry,我看了前半句没看后半句,误解了你的意思。
感觉我们的讨论有点跑偏,e2e 测试和单元测试其实是处在不同维度,解决的具体问题是不一样的,不能用来直接比较,不是一个非零即一的问题。 单元测试是验证代码逻辑问题,而不是验证业务逻辑问题。 相反,e2e 测试只能保证业务逻辑正确,但无法保证代码或软件是健壮的。(或者需要很大代价) |
19
PixelMage OP @index90
我个人的粗浅理解是,一些核心基础中间件之类的,单测,E2E 我觉得都不能少。 但是如果是一个业务系统的话,这可能就回到我提出的这个问题了~ 其实我个人的小心思是:既然业务 e2e 测已经 work 了,异常流也 cover 到了,单测带来的代码健壮提升 i don't care,毕竟后面还有 IDE,语言框架,lint, 代码风格检查,开发规约拉着我。 这样可以提高业务的落地速度,但是要是说后续的可维护可扩展性的,写单测应该是会有提高的,但是提高多大,就不太好说了,估计每个业务系统可能都不一样。 还是特别感谢你的回复,我收获了不少东西~~对单测的看法也没有那么片面了 |