单元测试有必要吗?

2021 年 12 月 12 日
 RuLaiFo

单元测试有必要吗?

我在现在的公司工作近半年了,公司的项目都需要写单元测试。但是写了这么久,感觉写单元测试费力不讨好,有时候写单元测试的时间大于写业务逻辑的时间,需要 mock 一大堆数据。要保证各种覆盖率,特别是分支覆盖率,需要覆盖到所写的每一个分支。

另外,大家写的单元测试质量参差不齐,因为感觉大家都是为了写测试而写测试,而不是真正的 tdd 。然而在迭代频繁,节奏紧凑的环境下,想要做到真正的 tdd ,还是有很大的难度的(个人觉得 tdd 实现需求会花更多的时间,可能是自己没正确认识和掌握 tdd?)。所以这就导致大家往往先去实现逻辑,再去写测试。

简而言之就是认为单元测试费时费力,又没有明显的收益,想请教一下大家怎么看待单元测试。

初次提问,如有不恰当的地方,请大家指出。

16949 次点击
所在节点    程序员
101 条回复
ayase252
2021 年 12 月 13 日
没有测试就没有重构的可能性,就只能屎上面糊屎。
nine
2021 年 12 月 13 日
@l00t
所以你要跑的是别人的单元测试,别人跑的是你的。

代码发布前,把所有测试都跑一遍,看看你改的代码,有没有让别人的代码蹦掉。

你写的单元测试主要是让别人跑的,别人写的是让你跑的。
l00t
2021 年 12 月 13 日
@nine 单元测试是测一个单元的,怎么跨单元看别人崩不崩?你说的根本不是单元测试!
3dwelcome
2021 年 12 月 13 日
写核心单元测试重要。

写逻辑部分的,代码一直在变,你怎么测试嘛。

不如全部逻辑写完后,把调试工具弄高效点,再多做自动化功能覆盖测试。
matrix1010
2021 年 12 月 13 日
@l00t 重要的其实是有测试,单不单元是很灵活的。

再摘录一段大佬的话: I will usually use mocks for that (I'm not a big fan of mocks, and prefer to avoid them wherever possible, but I think mocking network-comm responses is reasonable). Though "it depends": sometimes I do launch the software, but from within a test.
nine
2021 年 12 月 13 日
@l00t

所以说大部分开发都不知道“写单元测试”这个需求哪里来的。

你想象一下自己是软件发布员。你要对线上的软件发布一个小版本,只是一点 bugfix 。这种发布频率可能是 1 周 2 次,甚至初期 bug 不断,每天都会 fix 。

这时候不可能每次发布都要求测试人员把系统所有功能肉测一遍。但是 bug 得修,修了又不能不发。
你怎么知道别人修改的代码不会产生更大的 bug ,甚至把系统搞崩?
软件里面可能几万条逻辑,你想人肉全部测一遍几乎是不可能的。

在人肉检查关键点前,先跑一遍整体项目的测试代码。如果 A 写的代码,由 B 调用或者 C 继承。那么 A 的代码的改动有可能导致 B 和 C 出现 bug ,而他们不一定能做好整体的检查。也有可能 A 的代码是 D 改的,D 改的时候不清楚业务场景,认为没问题就发布了代码,也有可能 B 或 C 没时间仔细检查,也有可能 B 或 C 离职了,想问也没得问。

这时候几万个逻辑的单元的测试就起到了作用,帮助你快速的“初步”判定有没有问题,如果有问题,尽快打回去重新 debug 。要注意,仅仅是“初步”判定,后面对关键点该有的肉测还要有。但是这个初步过滤就能解决很多问题。稍微负责任点的开发,发布(不是提交)自己的代码前,就应该自己把所有测试跑一遍,进行初测。

而且“单元测试”并不是说最小粒度到 method 的这种才叫“单元测试”,单元要看你怎么拆。业务单元也是单元,只要这个流程中间不间断,没有异步,有明确的 input 和 ouput 就可以作为一个单元。你甚至可以不用在最小粒度写单元测试,只对拆分好的业务单元去写测试。


懂不懂单元测试,是程序员水平的一个分水岭。
招聘的时候只要问他对单元测试的理解,基本就能判断他开发水平怎么样了。
不知道单元测试的是票友。听说过没写过,或写过说不出所以然的是初级。而写过单元测试但强烈认为单元测试没用的,这种直接过滤掉。

并不是说程序一定要写单元测试。
1 不太复杂,且对不稳定库依赖不强的程序,可以不写,人肉就可以很快完成 debug 。
2 对质量要求不高的程序,主要是低价外包程序,这种写一句测试都是浪费时间。
3 验证 idea 类的程序,写出来只是为了给自己或者是别人看一下。
4 变动频繁的程序,创业的项目,业务流程经常发生摆动,而每一次重构,可能都是大刀阔斧结构性修改的。这种可能测试刚写完,代码就废了。这种如果成员开发水平一般,测试还是要写的。但是尽量不要去 TDD ,有可能致命。

前三种,基本写一下注释就好了。
第四种,如果开发者有很强的记忆力、控制力和责任心,对软件(自己开发的部分)每个细节都了然于心,每次修改代码都能严谨的去敲定需求和自测,可以不写。
sulfoh6
2021 年 12 月 13 日
@matrix1010
“首先,程序员是很容易犯低级错误的,就算是老司机也经常因为低级错误翻车。如果你的低级错误直到 QA 阶段才被发现是很严重的内耗,也会降低团队间的互相信任。”
//对不起,我看到的是单元测试发现的低级错误本身也是极其稀少,更多的低级错误可以通过代码审查、集成测试轻松地发掘出来。因为没写 UT 而让低级错误流到 QA 阶段,本身就反映了团队的能力堪忧。

“真的无能为力吗, 还是只是你们团队的技术水平不太够,或是你只是为了糊弄一下随便写个测试?”
//或者,能否请你举出些实例,关于单元测试能发现设计问题、性能问题、并发问题?在多线程 /进程下跑的用例还算单元测试吗?

“敏捷开发配合自动化测试配合严格的 Code Review ,再加上技术实力靠谱的团队,这样才能实现真正的高质量快速迭代,你可以专注于迭代新功能,而不是担心别人加了个功能 /改个功能把你原来能用的东西改坏了。”
//技术实力真的靠谱的话,没有单元测试照样能写出高质量代码。反之,如果水平有限,靠强制式的单元测试约束也没法阻止烂代码的产生。你不能把高水平个体的脑力劳动成果归结于单元测试流程的功劳。

“也别总是黑印度工程师,国内很多工程师可能并不如印度工程师。另外国内大厂很多是依靠很大的 QA 团队进行人肉测试,才确保了你用到的东西没问题。”
//我算黑他们吗?凭实际输出的代码质量客观评价而已。很大的 QA 团队进行人肉测试,在你这里成了减分项了是吧?别忘了 Windows 10 缺陷如此之多,原因之一是因为笃信自动化测试,解散了曾有的人工测试部门。我举的例子里的印度团队,也是漂亮的自动化测试指标霸榜,可是被发现的 Bug 们可以都把人蠢哭,但凡有个人类测过一遍也不至于那样。
sulfoh6
2021 年 12 月 13 日
在这里想认真问各位一句,你们经历过多少案例,是单元测试帮助持续地发现 Bug ?或者不要求持续,就是零星的低级错误也行。

是不是很费劲也想不起来?除了那些日常改了代码之后被单元测试卡咬、被迫更新用例的往事。

再问个问题,如果你们公司 /团队经费有限、人力有限、时间有限,需要在代码审查、单元测试、集成测试、系统测试(包括但不限于)几个环节中砍掉若干环节,你会优先考虑让哪个祭天?

不管有没有写入流程,但程序员在提交代码前自己跑一遍功能,基本验证一下,可以用自己搭的模拟环境,也可以用集成的验证环境,以保证不出纰漏,这应该也算一种最佳实践了吧。效果比单元测试好得多,成本也比单元测试低得多。事实上,在前互联网时代,很多传统软件公司就是这么做的,人家造的 Bug 并没有你黑得那么多。

总是把代码质量寄托在单元测试 + 自动化测试上,也难怪互联网时代这么多的半成品在把用户当小白鼠使。如果你认为这样很合理、很现代,那我也只能说人各有志了。
l00t
2021 年 12 月 13 日
@nine 你举的例子是自动化测试…… 这不是单元测试独有,写好了测试程序,都可以跑自动化测试……

固然单元划分可大可小,但是你连模块之间调用协作都测进去了,那你这单元划得也过于不讲理了。按你这么说甚至可以一个程序就算一个单元……天下所有测试无一不是单元测试……

不需要单元测试 不等于 不需要测试。你把单元测试的概念扩得太大了。
ericgui
2021 年 12 月 14 日
政治正确的说,当然有必要

但你有精力吗? 你们公司有那个时间给你写吗?
test0x01
2021 年 12 月 14 日
如果 pandas 这样的东西没有单元测试,你敢用吗
dayeye2006199
2021 年 12 月 14 日
大家扪心自问一下,没有单测的库 lib ,大家平时工作中敢用吗?
matrix1010
2021 年 12 月 14 日
早上醒来突然想到: 在国内这个开发几乎不写测试的环境下,做个低代码 /无代码测试平台可能挺有钱途。欢迎有钱有人脉的老哥联系我🧐
nine
2021 年 12 月 14 日
@l00t
这不是自动化测试兄弟。这就是单元测试。

自动化测试是把肉测自动化。
Joker123456789
2021 年 12 月 14 日
CICD 搞起来,pull request 搞起来,单测规范起来,必须要写完整的测试用例。

然后 如果有可能的话,不要用 mock ,直接跑真实代码,就直接操作(测试 /开发库)的数据。

说白了,单元测试就是针对 具体的某个方法,做一个完整的黑盒测试。 如果你们没执行到这个力度,那确实可以不玩。

这一套下来,你看看,测试阶段 bug 量会少多少。

你只看到了单测费力,但是没看到改 bug 的时间 被缩短了吗? 如果没,那只能说明你们的单测没执行到位。
Joker123456789
2021 年 12 月 14 日
@l00t 单元测试不是给你自测用的,不然你写个 main 方法不也可以解决问题吗? 或者用 postman 跑一下不也可以?

单元测试 是 你合并代码前,检查整个仓库用的,如果你改的东西 对别的地方造成了 bug ,那么在这个阶段 会立刻被发现。

配合 CICD ,在你提交 PR 的时候就可以做一个初步的 自动化测试。 你以为单元测试 只是在本地跑一下自测,就算影响了别人,也没人知道,但是实际上 单元测试 每次都应该是 全部跑一次的。 你影响了别人,别人的单测就会挂。 此时就会暴露出问题。

如果单元测试只是用来自测的,还能活到今天? 早就被抛弃了。
l00t
2021 年 12 月 14 日
你倒是说说 CI 里面的 I 是什么? 测试改动的东西对别的地方有没有造成 bug ,这是集成测试!!!

CI 阶段会跑自动化的单元测试和集成测试,而不是跑的都是单元测试!

真是概念都不清!
leeraya
2021 年 12 月 14 日
UT 确实是个好东西,这样就不怕别人提交的东西对你的代码部分做了错误改动了。
但是实际情况下,需求变更太频繁,ut 就变成了累赘。
目前我只在 github 开源项目提交时写过标准 ut 。
内部项目在开发的时候都不写。
caixiangyu17
2021 年 12 月 15 日
@sulfoh6 想不出例子的原因是每次改代码都得保证单元测试过,所以提交前就已经把挂掉的测试修好了。
但是没有单元测试的项目,改好一个 bug ,测试就把 ticket 打回来,因为把别的地方弄坏了的情况倒是遇到过好多次。
sulfoh6
2021 年 12 月 15 日
@caixiangyu17 其实在上面多次有人提到,如果你定义的单元测试都能发现修改本模块导致其它模块出问题,那这种粒度就不属于单元测试了,已经算集成测试了。单元测试是函数(方法)粒度的,其它模块在跑用例时理应 mock 了你的方法的行为。所以,对纯函数粒度的单元测试的疑问仍然在那里。我接触过的人几乎都没法具体说出单元测试究竟对生产力起了什么助力,只能语焉不详地干巴巴重复。在资源或者时间紧张时,大家又很诚实地用行动投票,单元测试通常第一个被祭天。解放出来的时间多跑几趟人工回归测试它不香吗?

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

https://v2ex.ih06.com/t/821608

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

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

© 2021 V2EX