我在现在的公司工作近半年了,公司的项目都需要写单元测试。但是写了这么久,感觉写单元测试费力不讨好,有时候写单元测试的时间大于写业务逻辑的时间,需要 mock 一大堆数据。要保证各种覆盖率,特别是分支覆盖率,需要覆盖到所写的每一个分支。
另外,大家写的单元测试质量参差不齐,因为感觉大家都是为了写测试而写测试,而不是真正的 tdd 。然而在迭代频繁,节奏紧凑的环境下,想要做到真正的 tdd ,还是有很大的难度的(个人觉得 tdd 实现需求会花更多的时间,可能是自己没正确认识和掌握 tdd?)。所以这就导致大家往往先去实现逻辑,再去写测试。
简而言之就是认为单元测试费时费力,又没有明显的收益,想请教一下大家怎么看待单元测试。
初次提问,如有不恰当的地方,请大家指出。
1
chendy 2021-12-12 10:03:18 +08:00
单元测试主要是能让人改东西的时候放心一些,改完了之后跑一下测试就知道有没有破坏之前的逻辑
越重要的功能越有必要写单元测试,盲目追求覆盖率不可取,毕竟大多数项目成本有限 |
2
matrix1010 2021-12-12 10:04:19 +08:00 via iPhone 1
实际上没多少公司是 TDD 的,但不代表不需要单元测试。看看大佬怎么说 https://twitter.com/mitchellh/status/1458478408749309960?s=21
|
3
vishun 2021-12-12 10:05:25 +08:00
现在安排你改个逻辑,然后部署到生产环境上,如果生产环境出错,可能就影响非常多的客户使用、可能造成真金白银的损失。你能确定你改的这个逻辑对其它的逻辑没有影响吗?你部署时不忐忑吗?单元测试最起码能检测出最基础的错误来。
当然小公司、内部使用,没多少人的话随便了。 |
4
dongcidaci 2021-12-12 10:13:35 +08:00 via Android
能百分之百保证自己写的代码没毛病吗,老铁
|
5
janxin 2021-12-12 10:16:02 +08:00
先去写逻辑再去写测试一般是增加 TDD 成本的最大元凶,先写测试就会提前考虑代码如何方便进行测试。另外写测试代码大于写业务代码时间是十分正常的事情,所以计算时间点的时候要预留出对应的空间。覆盖率在互联网开发团队可能是一个可以 trade-off 的东西,是要看团队的基线在哪里。落地 TDD 跟时间节奏有很大关系,如果项目本身就很时间紧张,那么 TDD 势必会导致两种选择:放弃 TDD 和项目延期。不过这个看情况是不需要你来决策的内容。
至于 TDD 的收益网上有很多文章介绍了,不如看看网上的文章,然后想一想:这些收益对我来说重要嘛? 另外,即便没有 TDD ,也一定要有集成测试 |
6
yishanhe 2021-12-12 10:19:20 +08:00
如果把 e2e,integration,unit tests 从上往下排起来,有人推荐应该是金字塔形(侧重在单元测试),也有人说应该是棱形(侧重在集成测试),我的经验是如果集成测试框架好,可以多写集成测试,单元测试重点保障关键的 local 逻辑,然后一定要有 coverage tool 这样只要综合的 coverage 够就行了
|
7
shateiel 2021-12-12 10:42:40 +08:00 1
我不爱写单元测试,但是我发自内心的觉得单元测试很重要。
|
8
VeryZero 2021-12-12 10:51:14 +08:00
如果规模较小,质量要求不高的项目确实没有必要。
但是如果大规模,高质量要求的项目,没单元测试就会陷入 BUG 越修越多的情况。。 |
9
RuLaiFo OP @chendy @vishun @dongcidaci
这个赞同,可以改的放心。但是除了单元测试,上线前都会有 QA 进行测试,不过也可能有漏测。 其实也会有许多公司不会严格执行单元测试,甚至不写单元测试,不知道一线大厂会不会不写单测?但是他们的项目其实也在正常运行,迭代,似乎单元测试又显得不那么重要了? |
10
cmdOptionKana 2021-12-12 11:05:10 +08:00
你想想,你去改别人的代码,没有单元测试,改完心里没底啊,如果手动测试,花的时间也不少。
别人改你的代码时,心情也一样。 你现在每天对着同一个项目折腾,当然对它很熟悉,但是如果你隔半年一年再回头看,也会感觉代码改起来心里没底。 小项目、初期开发需求变化剧烈、赶着上线、人手不足等等情况,可以暂时不写单元测试,但后续能补上最好还是补上,尤其是需要长期维护的项目,写单元测试的收益大于成本。 |
12
xtinput 2021-12-12 11:05:37 +08:00
写好单元测试后期修 bug 和维护的时间简单点,特别是颠覆性的维护的时候
|
13
ulosggs 2021-12-12 11:06:38 +08:00
碰到不写测试的队友和不懂测试重要性的 leader 就很烦。不想干活儿。
|
14
dingyaguang117 2021-12-12 11:08:14 +08:00
1. 迫使你思考边界
2. 自测出低级 BUG ,甚至是语法问题 3. 便于重构后快速验证 感觉 3 的持续性价值最大,很多情况是明知道系统是屎山但是又不敢动,如果有完善的测试用例是十分有利于开展重构工作的 |
15
binux 2021-12-12 11:12:27 +08:00 via Android 13
如果你的代码不能被单元测试,那么你的设计有问题。
|
16
RuLaiFo OP |
17
RuLaiFo OP @dongcidaci 即使有单元测试也不敢保证 100%呀,老铁,只是有单元测试,bug 概率更小😹
|
18
milkleeeeee 2021-12-12 11:16:57 +08:00
同意 15 楼的说法。我自己开发的软件之前也不写单元测试,后来改之前写过的代码的时候总是出 bug ,所以之后的代码我都会写单元测试。另外,单元测试能帮助我将代码进行拆分,以前我总是把大段大段代码写在一块,后来从单元测试的角度来思考之后,就会下意识的把一个功能分解成很多小的功能
总的来说我觉得虽然花的时间多了,但有了安全感、代码之间的松耦合度更低,更容易复用了,我觉得是值得的 |
20
liveoppo 2021-12-12 11:17:57 +08:00
关键业务部分写单元测试即可,处处写是追求形式,极大增加成本。
尤其前端,如果业务的实现在前端,该业务部分写一下,如果只是展示后端送过来的内容,不用写单元测试。 你还没写好单元测试呢,可能产品或 UI 就过来推翻方案重新设计了。 |
21
newtype0092 2021-12-12 11:22:48 +08:00 10
以前不怎么爱写,直接手动去测,什么 mock 之类的也都不用,就手动修改加注释掉不相关的逻辑,一次是挺快,反复测的时候这些零碎修改就很麻烦,得不停的 stash 和 copy paste 。后来直接写 unit test ,其实就是稍微花点时间把这些逻辑搞成能重复执行的,调试起来会方便不少。
方便反复测试调试其实并不是最重要的,单测最大的收益是可以改变你设计程序时的思考方式,先考虑输入输出,构思各种情况和边界 case ,把这些都落实成单测代码,这时再开始写功能代码,思路会更清晰,考虑的也更全面。很多时候一些混乱的逻辑都是因为一开始没搞清输入输出就着急下手导致的,这些就是导致 bug 的根源。 还有就是别觉得费力不讨好,能把单测写好把覆盖率拉满是很 NB 的技能,即使在现在的工作环境里不重要,但却是实打实加到你身上的技能点,以后肯定有很多产出质量大于数量的工作是需要这种技能的。很多人不是吐槽工作中什么都学不到么,其实就是没认识到很多东西的重要性觉得没必要。 |
22
matrix1010 2021-12-12 11:30:38 +08:00 via iPhone
其实我觉得所有代码都应该有测试,只是重要度低些的代码测一下功能正常就行,而重要度高的代码则要把各种情况都测一遍
|
23
meeop 2021-12-12 11:36:11 +08:00
我觉得作为程序员,理想情况,对代码质量有极致的要求,单元测试是重要和必须的,且必须覆盖 100%情况
但是,显然,做到上述完美单元测试是有巨大成本的 所以现实中,无非是一个取舍,质量要求越高,单元测试要求越高 反之代码不复杂,对错误容忍程度高,开发时间紧,那就不做或者少做单元测试 测试的意义就是减少 bug,只是一个方法,而不是法律 |
24
meeop 2021-12-12 11:39:15 +08:00
我还算在一个大厂,惭愧的说,从业至今很少写单测,也几乎没在项目里见过别人的单测,可能是我参与的项目不够重要
不过对于像数据库这种复杂且严谨,且基本是个单机服务的程序来说,单测显然是必须的 |
25
h82258652 2021-12-12 11:41:23 +08:00
15 楼说得太对了
无法写单元测试证明你的代码耦合度过高,无法 mock 楼主应该开心才对,小公司都不会给时间你写单元测试的,能跑( 2 种意思)就行了 |
26
MoYi123 2021-12-12 11:42:10 +08:00
我是觉得简单的 crud 代码没什么必要写测试, 本来就是一个把输入参数拼成 sql 的逻辑, 数据库端也被 mock 了. 单元测试里只能去根据参数看 sql 有没有拼对, 感觉没有起到什么作用.
对于能抽象出一些纯函数的代码, 单元测试就用很大用处了. |
27
gageshan 2021-12-12 12:36:20 +08:00
部门这个项目维护开发 6 年多了,两万多个 commit ,9700 多个 pr ,主要流程都有 ut 覆盖。每个 pr 要合入 master ,都必须跑一遍全部 ut 。
|
28
ClericPy 2021-12-12 12:41:03 +08:00
嫌麻烦就只写功能测试, 反正我已经被测试挡住无数次不向后兼容的 bug 了
看你项目 SLA 要求有多高了, 一般核心项目 coverage 再高都不过分, 毕竟现在大多数公司喜欢让你周五上线周六日免费加班, 测试越严格周六日上班几率越低 |
29
fengpan567 2021-12-12 13:18:39 +08:00
不写单元测试难道等着测试给你提 bug 么,嫌麻烦就不要追求覆盖率了,正常的分支能跑通就行
|
30
otakustay 2021-12-12 13:40:11 +08:00
问题可不就在“为了写测试而写测试,而不是真正的 tdd ”,那就应该去解决这个问题,而不是质疑单元测试有用没用吧
|
31
lewinlan 2021-12-12 13:51:38 +08:00 via Android
crud 业务代码硬要测试确实吃力不讨好,
我理解比较合理的实践是,不追求 100%覆盖,强迫自己划分边界,把抽象的东西提出来,再测, 100%覆盖并不就意味着没 bug 了 |
32
hingbong 2021-12-12 14:24:15 +08:00 via Android
工具类的话,还是很有必要的,业务部分就看情况吧
|
33
searene 2021-12-12 14:30:45 +08:00
如果你觉得单元测试太麻烦、需要很多 mock 工作的话,那么很有可能你的代码架构有问题。这句话很多人都说过,但到底什么样的代码架构才有利于单元测试却鲜有人提,我觉得具体可以看一下这本书,讲什么是好的单元测试,以及怎么设计代码架构才能从单元测试中获取最大的收益的,写得很好:
https://www.amazon.com/Unit-Testing-Principles-Practices-Patterns-ebook/dp/B09782L692/ref=sr_1_1?keywords=unit+testing&link_code=qs&qid=1639290414&sr=8-1 |
34
sagaxu 2021-12-12 14:31:19 +08:00
单元测试就像 “规律作息,自律饮食”。
每个人都知道这个好,这个重要,但是实践嘛,有人做的很好,然而大部分人完全做不到。 |
35
charlie21 2021-12-12 15:11:09 +08:00
付钱了吗,付单元测试的钱了吗,先付再写,付了就得写
|
36
timle1029 2021-12-12 15:24:16 +08:00
会写,而且必须要写
Unit test 的覆盖率不过关 build 就直接 fail ,至于覆盖率要求多少基本就是组内自己决定了,大部分在 90%左右 |
37
chenyu8674 2021-12-12 15:31:04 +08:00 1
能够有效避免修改代码时脑子浆糊搞出的低级错误
|
38
WilliamYang 2021-12-12 16:26:42 +08:00
如果你的代码质量过硬,我觉得不写也没什么,否则等到测试来提 bugs ,感觉双方挺浪费时间的
|
39
limao693 2021-12-12 16:29:25 +08:00 via iPhone
项目流水线,会自动计算覆盖率,打不到 80%,直接无法各入。好处就是,可以随心所欲小范围的代码重构,只要保证 UT 通过
|
40
pusidun 2021-12-12 16:55:41 +08:00
1.单元测试不仅是开发的活,实际上迭代初期测试不需要转测时,就需要介入到测试样例的编写上。没完全按照敏捷那套来吧。
2.你觉得浪费时间写,实际上如果这个错误在系统测试,集成测试甚至灰度发布阶段发现了,排错和修复的成本会是前一个阶段的 10 倍 |
41
smilingsun 2021-12-12 16:59:09 +08:00 via Android
不知道有没有这样的感受,修 bug 的时候是最需要想想是否要补一下 UT
|
42
wu67 2021-12-12 17:11:33 +08:00
别的不知道. 我是个前端打字员, 我只知道除了核心逻辑和几乎永远不会变的模块封装逻辑, 其他的业务代码写测试真是扯淡.... 且不说改动频繁与否, 但是在规定排期完成就够你喝一壶了
|
43
iyaozhen 2021-12-12 17:14:19 +08:00
个人觉得 tdd 实现需求会花更多的时间 可以肯定的说,是的
这个就看现在产品质量在什么阶段。比如一开始做一下接口测试,基本上能够 70 分了,再加上业务端的功能测试做到 80 分也很容易。但项目要想继续往下发展,质量要求更高的话,就需要整体来看了,比如需求流程、上线流程,还有就是代码阶段 CR 、UT 。这些都是需要投入之前几倍的精力只是为了做到 90 分以上。 就和高考一样吧,你要考 985 ,比本科就是要付出更多 |
44
akira 2021-12-12 17:20:31 +08:00
很有必要
|
45
2i2Re2PLMaDnghL 2021-12-12 17:25:20 +08:00 2
Write Everything Twice
重构的时候,因为你只改动一边,可以通过另一边进行确认改动是否正确 举个不是严格对照的例子,地球上稍复杂的物种的遗传信息都是 DNA 了( |
46
2i2Re2PLMaDnghL 2021-12-12 17:28:50 +08:00
不过我觉得既然都这么推 TDD ,又吹 Copilot
感觉就应该把测试写好,实际代码就 Copilot 生成( |
47
zhanlanhuizhang 2021-12-12 17:33:26 +08:00
我是非常想写,但是公司不给时间。
|
48
palemoky 2021-12-12 17:41:15 +08:00 1
我觉得很有必要。之前维护过某个大家日常几乎都在用的产品代码,各个业务线代码都是通过 if else 判断,一个方法能有一千多行,公司的业务快速发展导致代码迭代快,人员流动强,现在很多方法堆积在一起根本不敢随便动,大家改逻辑也是尽量加新的 if ,因为没有单元测试,你无法保证影响面可控,尤其是公司还是微服务架构,这种复杂度就更大了。
虽然上线前会有 QA 测试,但 QA 也只能测到他了解的范围,而无法测到他不知道的,这可能直接导致重大事故,而且随着公司的微服务化,人员间的沟通成本极大。有些 QA 不太懂开发,反馈问题只会说表现不符合预期,自己需要停下手里的活,打断思路去排查故障,可能查了几个小时候发现是一个很简单的问题,然后 QA 再去验证,QA 一般工作量也是很满,所以要等他有时间测试后再反馈结果,这样导致简单的问题一来一回浪费了不少的时间。 我去过两家大点的公司,我做的项目是都没有单元测试的,领导都是先上线、再优化,大家都是加班写 bug ,再加班改 bug 。因为公司 KPI 的原因,不少领导更乐于快速推进项目,而项目只要能跑就行,这样才更能让领导在述职有的讲,这种压力不断向下传达,最后到一线开发这里,原本两周的项目,就开始倒排一周加班搞定了。 |
49
opengps 2021-12-12 17:57:01 +08:00 via Android
如果你的程序每次修改不用保证其他地方不影响,那么可能用处不大,单元测试我的用法是,整体发布前的整体验证
|
50
palemoky 2021-12-12 18:01:34 +08:00
@palemoky 有了单元测试,不一定能解决上述的所有问题,但能带来很多非常多的收益:
1. 根据《代码大全》,越晚发现 bug ,纠正 bug 所付出的成本也就越高,而单测能够让开发者在开发阶段就及早发现一些 bug ,避免将 bug 带入联调或 QA 环节。尤其在微服务架构下,这种收益会更加的明显,尽可能减少高薪工程师的低效沟通,让他们更有时间去创造更多的价值。 2. 团队成员的开发水平一定是良莠不齐的,即便在上线前有 Code Review ,但这个阶段太晚了,除非代码有重大问题,一般都不会打回去,毕竟马上要上线了,一个开发写了一个 500+ 行的方法,重新修改意味着 QA 这部分的工作都白做了,极大影响上线时间,一般大家都不愿意背上上线卡自己这了。通过单元测试,能让开发者及早发现自己除了实现业务外,代码是否设计合理,及早纠正这个问题,从而提升团队的编码水平。 3. 单元测试能保证代码的健壮性,而不只是能跑就行。有些不重要的功能随着人员的流动,交接着交接着就没人知道这是啥了,但突然某天这个功能出了线上 bug 或者需要项目重构,根据之前的单元测试,让新手也能了解影响范围,保障项目质量。 |
51
janxin 2021-12-12 18:52:37 +08:00
@2i2Re2PLMaDnghL Copilot 重要的是写好评论
|
52
satoru 2021-12-12 19:56:44 +08:00
这里有几个概念,分开来可能比较好讨论:单元测试、测试覆盖率、TDD 。
分享一下我自己写测试的经验: 我一般是把单元测试当成一个效率工具,我会遵守“单元测试不能连接网络、不能连数据库”这样的规则,来确保我在开发时可以快速频繁执行单元测试,尽早发现错误。 但是测试覆盖率我一般不会刻意追求,特别是一些测试不好写的编程语言(例如 Go 的测试一般没有 Python 的好写),为了去覆盖某些分支可能要投入很多额外时间,这样就与我把单元测试作为效率工具的初衷就冲突了。不过这点很无奈,有些高管就喜欢去量化一些不好量化的东西,而不幸的是,测试覆盖率一般是他们拍脑袋容易想到的一项指标。 TDD 我很少实践,虽然偶尔刚创建新项目时会有热情去尝试,但是时间长了又回到原来先写实现再管测试的模式,后面慢慢就顺其自然了 …… |
53
tyrantZhao 2021-12-12 20:01:52 +08:00
需求变化大,排期紧张,就没有必要
|
54
wyx119911 2021-12-12 20:03:49 +08:00
我觉得比较合理的是,基础组件开发写单测,关键业务由质量管控团队(一般是测开)写接口拨测。
|
55
picone 2021-12-12 21:36:08 +08:00
单元测试我觉得是可以针对不同的情况进行测试。
比如我写一个接口,我要找到走到某个逻辑的 case 很难,但是我通过单测 mock 数据能很轻易走到哪个逻辑,那我开发的时候就能很好调试了。 如果你养成习惯使用单测来调试开发的代码,你就不觉得单测是累赘。 |
56
l00t 2021-12-12 23:39:18 +08:00 1
单元测试没必要,不写。有功能测试就行了。
功能测试相对来说输入输出更稳定,测试用例的选择和对输出的预期都从业务而来,业务不变用例就可以不变。而单元测试是白盒测试,要追求覆盖率的话,代码怎么写你就得怎么测,改一次代码没准还得给改一次测试,改了之后测试程序自己没准还引入了新 bug ,没完没了。 并且,程序出 bug 大多数时候是没想到,而不是笔误写错。功能测试一般都是黑盒,无所谓你程序怎么写,输入输出只考虑业务需求,相比单元测试更有意义也更容易覆盖没想到的意外情况。功能的概念还大点,可能由多个单元组成,在一些校验方面也更容易做责任划分。 |
57
curoky 2021-12-12 23:44:09 +08:00 via Android
基础库一定要写的,可不是开玩笑的;业务就没必要了吧,不是专门招了 QA 干这活吗?
|
58
elfsundae 2021-12-13 00:00:32 +08:00
太有必要了,尤其是公共库、基础组件等,这是应用稳定的最基础。
当然,如果老板只关心需求啥时能搞完,那就别写了。KPI 优先级大于一切。 |
59
nine 2021-12-13 00:20:59 +08:00 2
高质量的软件,必须要有单元测试。
没改过线上运行中的复杂的项目,一定不知道单元测试的意义。 改过线上运行中的复杂的项目,也未必知道单元测试的意义。 如果一个项目很复杂,那么在修改局部的时候,很有可能牵一发而垮全身。你不会知道项目里有多少代码调用你,或是继承你。 如果改的是别人的代码,没有单元测试,改完直接上线,后果不堪设想。如果恰巧是个金融项目,分分钟能让你公司破产。 当然,你的需求方可能并不要求你的代码质量。 而单元测试不等于 TDD ,事实上能真正合格的实施 TDD 的项目可能也就是 1%。 |
60
l00t 2021-12-13 00:51:40 +08:00
@nine 这我就要杠一下了。多少代码依赖你继承你调用你,这你做了单元测试也不知道啊。你修改局部,然后通过了这个局部的单元测试,爽了对吧,然后别的地方崩掉了。这种场景你需要的是系统回归测试而不是单元测试。
|
61
kaedea 2021-12-13 02:50:17 +08:00 via Android
单元测试是快速调试代码的最好切面。
|
62
msg7086 2021-12-13 04:54:19 +08:00 via Android
独立的功能代码做单元测试,其他地方用功能(集成)测试覆盖就行了。关键在于自动化测试覆盖绝大多数代码,而不是纠结这个测试是不是单元测试。
|
63
damai0419 2021-12-13 09:28:30 +08:00
有必要... 没时间...
|
65
abcbuzhiming 2021-12-13 09:37:36 +08:00
@vishun 实践表明单元测试并不能保证检测出你所说的“基本的错误”,因为单元测试的执行过程本身也是业务逻辑的一部分。不要过于抬高单元测试,测试是必要的,但是单元测试也只是测试的一种手段而已,它能测试出来的东西用别的测试方法照样可以,同样的,有些很难弄出来的隐藏的问题,单元测试照样测不出来。这东西不是银弹,不要觉得这东西存在就能解决一切问题。
就目前来讲,单元测试这东西在规模不大的公司里演变成了老板不搞测试降低成本,变相给程序员加单位时间工作量的工具(要求写单元测试,却不允许延长项目时间)了。所以我个人建议是,如果你待的公司很正规,那你就按要求写单元测试,如果你待的公司不那么正规,老板是拿单元测试来压榨你们,那就想尽一切办法别写单元测试 |
66
powerman 2021-12-13 09:43:31 +08:00
没有必要,单元测试只是一个仁者见仁,智者见智的事情,要根据项目实际情况以及开发人员的能力来做,首先要做的就是分层设计,哪些是业务逻辑,哪些是技术上的东西,耦合在一起是最难测试的,然后技术上的很多代码是没必要测试,因为很多不复杂,也没必要去做。
另外单元测试是要有懂技术的 leader 才有意义,像我在携程这个破公司,上头 leader 就 SB 地要求分支覆盖率跟行数覆盖率,然后我们没有用 JSR303 注解参数校验,一大堆的 if-else 判断参数是否为空,结果你发现单元测试编写的时间,全耗费在简单的参数校验逻辑 case 上了,真正重要业务逻辑的 case 校验反倒没人写,反正我现在写了个脚本,自动生成这些参数校验的单元测试让覆盖率上去,自己懒得动手测了 |
67
pkoukk 2021-12-13 09:57:56 +08:00 1
经历过太多的项目了,如果不写 ut ,一个较大项目的可维护寿命一般就两年,两年之后就成一坨腐肉,没人愿意动了。
因为你无法判断你这一次的修改变更是否影响到了其他模块,而且两年的时间项目的初始成员应该也所剩不多了,那些没有测试覆盖的地方只能靠读代码去理解 而不写 ut 的代码一般都很烂,因为为了写 ut 必然要进行模块间的抽象,不然没办法 mock ,而没有 ut 的项目很多都放飞自我,能明显看出不同贡献者直接显著矛盾的设计逻辑 |
68
wuqiangroy 2021-12-13 10:07:42 +08:00
你在写 unit test 的时候有没有发现代码 bug 呢?
这就是写 unit test 的价值所在。 |
69
nameyukan 2021-12-13 10:11:36 +08:00 2
如果你的工程构建一次需要半个小时,那么你是否会有这么个小冲动,这段代码老子可以写单测的话,是不是就不用在写逻辑的时候要构建一遍才能验证了?
不能写单测的代码不一定烂,不能写单测的工程架构基本上过一段时间就烂。 把单测当成一种开发手段,也许能好受很多。 |
70
leeg810312 2021-12-13 11:13:51 +08:00 via Android
单元测试一定要做,现在正在参与一个产品,1 年多了,至少有 50%以上的代码是我写的,而且经常会因为特性变更而重构部分核心代码,虽然商务方面压力大,开发计划很少有留给写单元测试的时间,但至少在核心模块都抽时间写单元测试,保证关键功能 bug 少,可以减少集成测试出 bug 的概率
|
71
yule111222 2021-12-13 11:18:20 +08:00
建议试试 ATDD (验收测试驱动开发)
纯粹的单测颗粒度太小,适合对一些核心的类来做,比如 DDD 架构里面的领域对象,或者一些工具类 |
72
chunquchunyoulai 2021-12-13 11:19:25 +08:00
TDD 是
1. 先写一个失败的测试 2. 写只让失败的测试通过的代码逻辑 3. 重构 ---- 而这 3 个点会对应以下几个点,并且会让你的关注点分离(一次只关心一件事) 1. 写测试 是为了只关注功能需求 2. 只关注让功能需求实现 3. 重构是关注代码设计 |
73
Raos 2021-12-13 12:18:11 +08:00
有必要,不必须
|
74
sulfoh6 2021-12-13 12:32:31 +08:00 2
单元测试和代码质量没有必然联系。首先用例都是在白盒的前提下设计,为了刷覆盖率,有很多种办法可以很鸡贼地避开边界,流水账一样走一遍过场,把字面的覆盖率做得足够漂亮。一个团队里你不能保证每个人都会在写用例时尽心去考虑边界,总有人能糊弄出覆盖率达标的稀烂代码。但如此花费极大的时间代价去凑覆盖率,还有意义吗?
我呆过的一个 MNC 公司里很多印度团队,他们搞 pipeline 的漂亮花哨程度可以把上层哄得不要不要的,单元测试覆盖自然是完美级别的,还有各种自动集成测试。然而,服务上线以后会花样扑街,出错错到匪夷所思。经常在救火,但往往一波未平一波又起。到底是哪个环节出篓子了呢?单元测试 90%以上的代码仍然是把用户、内部用户当小白鼠,藏满各种地雷。 也许你有过体会,写单元测试过程中可以顺手解决掉几个低级错误。但基本上就到此为止了。很多设计上的问题、接口的问题、性能问题、安全问题、并发问题...,单元测试都无能为力,必须得靠人工的系统测试来暴露。所以,我们为什么又得花这么大的工作量去刷覆盖率呢?单元测试的另一个副作用是巩固强化了旧有的设计与实现,让决策人在决定是否重构时畏首畏尾,也让每一次的代码更改变得无比磨叽,强制加到构建过程里也会浪费更多的时间。 从个人经历来看,虽然只是有限的视角,但已经很明显的看到讽刺性的一幕:零单元测试的商业产品,稳定地运行在客户的环境里,缺陷率在可预期范围里。这里还包括电信级的设备。另一面是追求覆盖率的产品,都还没到客户手里,内部已经炸开花了,坑了内部合作的团队。因为伴随着单元测试的还有敏捷开发的其它要素,势必让依赖内部基础库的其它产品团队充当小白鼠。当然这并不是单元测试本身的锅,问题还是出在人身上。但单元测试充当了很鸡肋的角色。也许在某些关键的算法上,适合用单元测试去查瑕疵;而对于 CRUD 或者接口层面的代码,写单元测试纯粹是走形式。为什么要欺骗自己呢? |
75
GiantHard 2021-12-13 12:36:44 +08:00 via Android
如果只是 crud ,那么写单元测试收益不大。
如果你的 crud 开始包含业务逻辑,那么你需要考虑怎么把业务逻辑跟 crud (也就是读写数据库或第三方 API )隔离开,这时单元测试的收益就比较明显了。 |
76
xylophone21 2021-12-13 12:38:07 +08:00
说重构的,问一下你们重构的时候,只重构单个函数吗?否则如果函数改了,单测不一样要跟着改?除非是核心模块,保持一定的稳定性,但一个项目中,能有多少是核心代码呢?甚至有没有核心代码呢?
最近在看 Apple 、Google 开发的 Matter (一个物联网协议)的代码,CI 里确实配置了一大堆 test ,但基本上也是集成测试为主,客户端给服务端发一个什么包,期待收到一个什么回复之类的。mock 了做单测的,几乎没有。虽然在代码走读的过程中,他们会非常重视这个代码可否做单测。 |
77
matrix1010 2021-12-13 13:00:26 +08:00
@sulfoh6 "写单元测试过程中可以顺手解决掉几个低级错误。但基本上就到此为止了" 首先,程序员是很容易犯低级错误的,就算是老司机也经常因为低级错误翻车。如果你的低级错误直到 QA 阶段才被发现是很严重的内耗,也会降低团队间的互相信任。
"很多设计上的问题、接口的问题、性能问题、安全问题、并发问题...,单元测试都无能为力" 真的无能为力吗, 还是只是你们团队的技术水平不太够,或是你只是为了糊弄一下随便写个测试? "因为伴随着单元测试的还有敏捷开发的其它要素,势必让依赖内部基础库的其它产品团队充当小白鼠" 敏捷开发配合自动化测试配合严格的 Code Review ,再加上技术实力靠谱的团队,这样才能实现真正的高质量快速迭代,你可以专注于迭代新功能,而不是担心别人加了个功能 /改个功能把你原来能用的东西改坏了。当然,有测试的话甩锅也比较方便。 "我呆过的一个 MNC 公司里很多印度团队,他们搞 pipeline 的漂亮花哨程度可以把上层哄得不要不要的" 也别总是黑印度工程师,国内很多工程师可能并不如印度工程师。另外国内大厂很多是依靠很大的 QA 团队进行人肉测试,才确保了你用到的东西没问题。 |
78
sockpuppet9527 2021-12-13 13:43:33 +08:00
|
79
ah64zzpk 2021-12-13 14:07:02 +08:00
作为一个曾经的软件测试,这个帖子看了让我感觉很欣慰啊,还是有很多开发人员重视代码质量和单元测试的啊
|
80
libook 2021-12-13 14:20:59 +08:00
一方面单元测试只是一种手段,有没有必要还是得看你们工作痛点是什么;
另一方面任何方法想要发挥最大效用就得按照核心思想来做,应付的话相当于没用。 |
81
ayase252 2021-12-13 14:22:35 +08:00 via iPhone
没有测试就没有重构的可能性,就只能屎上面糊屎。
|
82
nine 2021-12-13 14:38:45 +08:00
|
84
3dwelcome 2021-12-13 16:56:18 +08:00
写核心单元测试重要。
写逻辑部分的,代码一直在变,你怎么测试嘛。 不如全部逻辑写完后,把调试工具弄高效点,再多做自动化功能覆盖测试。 |
85
matrix1010 2021-12-13 17:57:34 +08:00
@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. |
86
nine 2021-12-13 19:54:15 +08:00
@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 ,有可能致命。 前三种,基本写一下注释就好了。 第四种,如果开发者有很强的记忆力、控制力和责任心,对软件(自己开发的部分)每个细节都了然于心,每次修改代码都能严谨的去敲定需求和自测,可以不写。 |
87
sulfoh6 2021-12-13 22:01:01 +08:00
@matrix1010
“首先,程序员是很容易犯低级错误的,就算是老司机也经常因为低级错误翻车。如果你的低级错误直到 QA 阶段才被发现是很严重的内耗,也会降低团队间的互相信任。” //对不起,我看到的是单元测试发现的低级错误本身也是极其稀少,更多的低级错误可以通过代码审查、集成测试轻松地发掘出来。因为没写 UT 而让低级错误流到 QA 阶段,本身就反映了团队的能力堪忧。 “真的无能为力吗, 还是只是你们团队的技术水平不太够,或是你只是为了糊弄一下随便写个测试?” //或者,能否请你举出些实例,关于单元测试能发现设计问题、性能问题、并发问题?在多线程 /进程下跑的用例还算单元测试吗? “敏捷开发配合自动化测试配合严格的 Code Review ,再加上技术实力靠谱的团队,这样才能实现真正的高质量快速迭代,你可以专注于迭代新功能,而不是担心别人加了个功能 /改个功能把你原来能用的东西改坏了。” //技术实力真的靠谱的话,没有单元测试照样能写出高质量代码。反之,如果水平有限,靠强制式的单元测试约束也没法阻止烂代码的产生。你不能把高水平个体的脑力劳动成果归结于单元测试流程的功劳。 “也别总是黑印度工程师,国内很多工程师可能并不如印度工程师。另外国内大厂很多是依靠很大的 QA 团队进行人肉测试,才确保了你用到的东西没问题。” //我算黑他们吗?凭实际输出的代码质量客观评价而已。很大的 QA 团队进行人肉测试,在你这里成了减分项了是吧?别忘了 Windows 10 缺陷如此之多,原因之一是因为笃信自动化测试,解散了曾有的人工测试部门。我举的例子里的印度团队,也是漂亮的自动化测试指标霸榜,可是被发现的 Bug 们可以都把人蠢哭,但凡有个人类测过一遍也不至于那样。 |
88
sulfoh6 2021-12-13 22:34:38 +08:00
在这里想认真问各位一句,你们经历过多少案例,是单元测试帮助持续地发现 Bug ?或者不要求持续,就是零星的低级错误也行。
是不是很费劲也想不起来?除了那些日常改了代码之后被单元测试卡咬、被迫更新用例的往事。 再问个问题,如果你们公司 /团队经费有限、人力有限、时间有限,需要在代码审查、单元测试、集成测试、系统测试(包括但不限于)几个环节中砍掉若干环节,你会优先考虑让哪个祭天? 不管有没有写入流程,但程序员在提交代码前自己跑一遍功能,基本验证一下,可以用自己搭的模拟环境,也可以用集成的验证环境,以保证不出纰漏,这应该也算一种最佳实践了吧。效果比单元测试好得多,成本也比单元测试低得多。事实上,在前互联网时代,很多传统软件公司就是这么做的,人家造的 Bug 并没有你黑得那么多。 总是把代码质量寄托在单元测试 + 自动化测试上,也难怪互联网时代这么多的半成品在把用户当小白鼠使。如果你认为这样很合理、很现代,那我也只能说人各有志了。 |
89
l00t 2021-12-13 22:44:13 +08:00
@nine 你举的例子是自动化测试…… 这不是单元测试独有,写好了测试程序,都可以跑自动化测试……
固然单元划分可大可小,但是你连模块之间调用协作都测进去了,那你这单元划得也过于不讲理了。按你这么说甚至可以一个程序就算一个单元……天下所有测试无一不是单元测试…… 不需要单元测试 不等于 不需要测试。你把单元测试的概念扩得太大了。 |
90
ericgui 2021-12-14 06:40:35 +08:00
政治正确的说,当然有必要
但你有精力吗? 你们公司有那个时间给你写吗? |
91
test0x01 2021-12-14 08:34:21 +08:00 via Android
如果 pandas 这样的东西没有单元测试,你敢用吗
|
92
dayeye2006199 2021-12-14 08:40:10 +08:00 1
大家扪心自问一下,没有单测的库 lib ,大家平时工作中敢用吗?
|
93
matrix1010 2021-12-14 10:14:48 +08:00
早上醒来突然想到: 在国内这个开发几乎不写测试的环境下,做个低代码 /无代码测试平台可能挺有钱途。欢迎有钱有人脉的老哥联系我🧐
|
95
Joker123456789 2021-12-14 16:30:03 +08:00
CICD 搞起来,pull request 搞起来,单测规范起来,必须要写完整的测试用例。
然后 如果有可能的话,不要用 mock ,直接跑真实代码,就直接操作(测试 /开发库)的数据。 说白了,单元测试就是针对 具体的某个方法,做一个完整的黑盒测试。 如果你们没执行到这个力度,那确实可以不玩。 这一套下来,你看看,测试阶段 bug 量会少多少。 你只看到了单测费力,但是没看到改 bug 的时间 被缩短了吗? 如果没,那只能说明你们的单测没执行到位。 |
96
Joker123456789 2021-12-14 16:40:50 +08:00
@l00t 单元测试不是给你自测用的,不然你写个 main 方法不也可以解决问题吗? 或者用 postman 跑一下不也可以?
单元测试 是 你合并代码前,检查整个仓库用的,如果你改的东西 对别的地方造成了 bug ,那么在这个阶段 会立刻被发现。 配合 CICD ,在你提交 PR 的时候就可以做一个初步的 自动化测试。 你以为单元测试 只是在本地跑一下自测,就算影响了别人,也没人知道,但是实际上 单元测试 每次都应该是 全部跑一次的。 你影响了别人,别人的单测就会挂。 此时就会暴露出问题。 如果单元测试只是用来自测的,还能活到今天? 早就被抛弃了。 |
97
l00t 2021-12-14 17:36:05 +08:00
你倒是说说 CI 里面的 I 是什么? 测试改动的东西对别的地方有没有造成 bug ,这是集成测试!!!
CI 阶段会跑自动化的单元测试和集成测试,而不是跑的都是单元测试! 真是概念都不清! |
98
leeraya 2021-12-14 19:33:19 +08:00
UT 确实是个好东西,这样就不怕别人提交的东西对你的代码部分做了错误改动了。
但是实际情况下,需求变更太频繁,ut 就变成了累赘。 目前我只在 github 开源项目提交时写过标准 ut 。 内部项目在开发的时候都不写。 |
99
caixiangyu17 2021-12-15 08:18:10 +08:00
@sulfoh6 想不出例子的原因是每次改代码都得保证单元测试过,所以提交前就已经把挂掉的测试修好了。
但是没有单元测试的项目,改好一个 bug ,测试就把 ticket 打回来,因为把别的地方弄坏了的情况倒是遇到过好多次。 |
100
sulfoh6 2021-12-15 11:12:20 +08:00 via Android
@caixiangyu17 其实在上面多次有人提到,如果你定义的单元测试都能发现修改本模块导致其它模块出问题,那这种粒度就不属于单元测试了,已经算集成测试了。单元测试是函数(方法)粒度的,其它模块在跑用例时理应 mock 了你的方法的行为。所以,对纯函数粒度的单元测试的疑问仍然在那里。我接触过的人几乎都没法具体说出单元测试究竟对生产力起了什么助力,只能语焉不详地干巴巴重复。在资源或者时间紧张时,大家又很诚实地用行动投票,单元测试通常第一个被祭天。解放出来的时间多跑几趟人工回归测试它不香吗?
|