作为从事软件开发多年的资深码农,看遍了各种事故和火葬现场。在接触测试驱动开发以及敏捷之后,发现这正是解决 bug 丛生、issue 漫天,最终导致 996 、007 修 bug 的困境。
这里将单元测试的一些看法分享给大家,希望能够提供一些启发。英译版同步发布在 dev.to,欢迎一起交流学习。
下面是正文。
"开发安全可靠的应用程序的最好方式,就是不写代码。"--Kelsey Hightower
很多开发者应该或多或少听过单元测试( Unit Tests ),甚至编写过,也或许对其有所了解。不过,在如今瞬息万变的环境下,单元测试似乎正在成为鸡肋。程序员们都知道它的好处,但是对其显得比较冷淡。“进度这么赶,还有什么时间写单元测试呢?”这样的话是不是听着很熟悉?
所谓单元测试,简而言之就是程序员编写测试代码来验证自己写的功能代码是否能按照要求运行。如果测试代码不能通过,就说明自己写的功能代码是有问题的。
这种自己测自己的方式似乎有些可笑,相当于考试时看着答案做题。然而在测试领域,这样的方式有个专业术语叫白盒测试。而白盒测试的对立术语叫黑盒测试,也就是用其他方式来验证。单元测试属于白盒测试,而更高级的测试例如集成测试( Integration Tests )、端到端测试( End to End Tests )、UI 测试( UI Tests ),都属于黑盒测试。单元测试仅仅是测试代码本身。
单元测试在敏捷开发( Agile Development )中是非常有用的工具。甚至有些敏捷框架,例如极限编程( XP ),就要求每一个功能必须被单元测试覆盖。在之前的文章《浅谈敏捷:你的团队在正确实践敏捷吗?》就提到过单元测试的重要性。
概括来说,单元测试有下面几个重要作用:
因此,表面上来看,单元测试对于软件开发来说会带来比较大的收益。
单元测试可以提高我们的产品质量、测试效率,那为什么程序员还是不喜欢写单元测试呢?据 JetBrains 统计,被调查者中仅有 57% 要写单元测试,仅有 35% 会在大部分项目中实施自动化测试。
那么,为什么?有几个可能的主要原因:
然而,这几个原因都经不起推敲:第一,长期来看自己修复 bug 写的代码量肯定远不止这么点;第二,不管是多么牛逼的程序员,代码写多了,根据大数定理,都会有失误的时候;第三,简单功能如果被引用多了,也会变得重要;第四,QA 的主要工作是保证整体质量,而单元测试是保证局部质量,缺陷部件组装出的产品会优质么?
其实,这里最主要的原因是思维模式,程序员大部分时候会站在个体的角度,思考短期的问题,从而忽略了长期的成本收益。作为一个合格的开发者,最主要目标是用最有效的方式开发出最大价值的功能。因此,单元测试在短时间内无法创造价值,从而被很多人忽视。
单元测试就像读书,短期内不能让人知识渊博、名利兼收,但长期来看是会有效果的。单元测试如果成为习惯或组织文化,就会更容易打造高质量产品和持续交付。要在团队中推广单元测试,需要更根本的流程,例如极限编程、测试驱动编程,或者更高决策者,例如 CTO 、架构师。
如果您对笔者的文章感兴趣,可以加笔者微信 tikazyq1 并注明 "码之道",笔者会将你拉入 "码之道" 交流群。
本篇文章英文版同步发布在 dev.to,技术分享无国界,欢迎大佬们指点。
![]() |
1
Twnysta 163 天前
以前写,但是赶不上业务。然后就都放弃了。
|
3
test4zhou 163 天前
通用函数会写
|
![]() |
4
learningman 163 天前
主要是不好拆,函数本身好测,但是要 mock 可太麻烦了
|
![]() |
5
SHF 163 天前 ![]() 写 4 年代码到现在,没刻意的写过测试,一般的来说跑起来试一试就能发现问题。在代码中做好 assert 就够了。有写测试代码的时间,不如多想想实现的逻辑,或者在写代码前做好设计。
|
6
error101 163 天前
前端怎么写单元测试比较好
|
7
dayeye2006199 163 天前 ![]() 之前试过 TDD ,发觉在搞增删查改的时候并没有想象中顺手。
知道我开始写一些框架类代码的时候,才发觉 TDD 的好处。思路非常的自然,先站在用户的角度想别人要怎么使用你的框架,然后写出测试用例,最后去补实现。 这样写出来的框架,质量既稳健,同时又能站在用户的交付思考很多使用难易度的问题,非常的有帮助。 |
![]() |
8
knightgao2 163 天前
来个前端的 real world 项目,我来学学 TDD 的怎么写
|
9
coldmonkeybit 163 天前
借楼请教一个问题,我是完全没有测试经验的小白,在实际业务中想测试一个接口是怎样写的。
例如一个 post 新增接口,会同时操作几张表,那我每测试一次数据库中就会多几条数据么? 还是会通过其他手段模拟数据呢 |
![]() |
12
lysS 163 天前 ![]() @coldmonkeybit #9 ut 一般是针对一个函数,你这个太大了。不过非要测也可以,只不过测试环境要数据库,post 完了再读出来看看是否符合期望
|
13
wszzh 163 天前 ![]() @coldmonkeybit 用我有限的测试经验回答你,可以建一个测试数据库,使用 flyway 这类软件,测试执行前往测试数据库插入一些测试数据,测试结束清除数据库
|
![]() |
14
tikazyq OP @dayeye2006199 是的,经历了社会毒打,才知道来之不易的幸福 hhhhh
|
![]() |
16
wolfie 163 天前
不写,没什么好处,而且大多数人 mvn skip test 都不会。
涉及到升级依赖版本时候,挺有用的。 |
![]() |
17
unco020511 163 天前
客户端写起来非常非常麻烦,且收益不大
|
![]() |
18
tikazyq OP @knightgao2 可以关注微信公众号“码之道”( codao_blog ),后续会有关于前端单元测试的更新
|
![]() |
19
tikazyq OP ![]() @coldmonkeybit 这涉及到单元测试和更高级一点的接口测试了。就单元测试来说,颗粒度更小,已于操控,如果有依赖的话,可以采用 mock 的方式来解决,因为单元测试只是测试代码本身;接口测试就属于黑盒测试,用 postman 之类的工具就可以了
|
![]() |
20
rodrick 163 天前
react hooks 之后就不写单测了 难以突出 unit 的概念
|
![]() |
25
wupher 163 天前 ![]() 很有好处,尤其是有问题可以直接回归测试,发版本前自动测试。
业务越复杂,mock 越麻烦。 有专门测试数据库,但是数据库表的测试数据维护又是另外一个麻烦和依赖。 测试让代码可维护可依赖。但有时候测试代码本身又需要维护和依赖。TDD 不是坏事,只是,嗯,要看业务和管理是否愿意承认它的价值和代价了。 |
![]() |
26
tikazyq OP @unco020511 客户端没怎么接触过,不知道 ut 是否能有收益
|
27
urnoob 163 天前
业务开发不要写单元测试!!!!!!!!!!!!!
|
![]() |
29
tikazyq OP @wupher 很有道理,大佬应该是 TDD 专家,看起来很有经验。UT 的收益一般在代码覆盖率不饱和的情况下收益很大,越到后面边际效应越明显,所以中庸之道才是正解
|
![]() |
31
frank1256 163 天前
项目刚开始开发,不稳定,写单测来不及写就业务变化了。稳定后再补充单测。提交代码时会走单测和自动化测试脚本,过了才可以 review
|
33
JasonLaw 163 天前 ![]() @dayeye2006199 #7 &t=577s - Write Your Tests First!
|
34
zhuweiyou 163 天前
又不是做开源, 业务开发不写, 测试没写完, 需求又改了.
|
![]() |
35
james2013 163 天前
不写
写单元测试是额外的时间,需要加班 而且需求改了后,是不是又要重新写? |
![]() |
36
GeorgeGalway 163 天前 ![]() 国内的单元测试会加速内卷
|
![]() |
37
hsuyeung 163 天前
以前不写,在学习如何写。
借楼问下,我有一个方法,根据传入参数会有多种不同的错误信息。我应该是为每一种情况编写一个测试方法还是在一个测试方法里把所有情况都写一遍? |
38
coldmonkeybit 163 天前
@tikazyq 十分感谢,很有帮助
|
![]() |
39
rekulas 163 天前
基本不写 个别项目偶尔会写-时间很充裕的情况下
写测试比开发还费时间,更大的问题实际测试异常复杂 单测压根覆盖不了多少情况,性价比极低 |
![]() |
40
rekulas 163 天前
我们都是开发完了把所有开发完了人工测试一遍所有可能相关的流程,虽然麻烦但是稳
|
![]() |
41
yagamil 163 天前
靠经验 , 自己用 postman 测试
|
![]() |
42
marcong95 163 天前
同蹲一个前端单元测试项目开开眼。。。
|
![]() |
43
litmxs 163 天前 via Android
写
要求行覆盖率 80%以上,函数覆盖率 100% 单元测试写的比较完善的话,修改代码后跑一遍单元测试就能验证改动是否有问题 |
44
anonydmer 163 天前
@hsuyeung 这个没有固定的模式,你这两种方法都很常见,选择自己认为合理的好维护的就可以。 比如你这个参数的逻辑要改的时候,可以很方便的先定位到对应的单元测试代码中去即可。 我个人一般喜欢把常规逻辑和边缘性的异常情况分开来成不同的方法写
|
45
saberlong 163 天前 via Android
写框架,函数库,基础设施时写比较好。业务的话,业务复杂起来后,维护成本很高。比如测试用例的执行顺序变化和并发执行时,会导致新增单测在单跑时正确,全部一起跑时就可能有时正确有时错误,维护非常耗时间。
|
![]() |
46
hsuyeung 163 天前
@anonydmer 我自己目前也是更倾向于每种情况一个测试方法,这样每个测试方法很容易一眼看懂逻辑。但是这样没法直观地看到有哪些可能的情况(需要去把每个方法都看看)。所以有点纠结了。
|
47
microxiaoxiao 163 天前 via Android
三天两头修改就别写了,前两天 BA 让修改个字符串大小写,下划线。自动化测试的姐姐一通抱怨。
|
![]() |
48
ericgui 163 天前
今天花了 30 分钟修了一个 bug ,花了 2.5 小时写 test case
因为一个时间有关的函数,本地机器和服务器机器不在一个时区,这就很傻逼 |
49
jones2000 163 天前
单元测试还要开发写, 不是测试组写的吗
|
![]() |
50
GiftedJarvis 163 天前
之前的公司单元测试和集成测试都会写, 现在公司的屎山, 写测试太恶心了
|
51
vivipure 163 天前
前端业务代码不写,组件库和 SDK 开发写
|
![]() |
52
Rooger 163 天前 ![]() - 最近也有想法,写一篇关于自己对单元测试的看法。无奈身体不适,暂时还没有动,所以先在此处写下自己的观点,但愿能帮助一些迷茫的同学。
- 简单介绍自己的经历,9 年游戏后端,开始用 C++,后面转 Go ,都没有意识到单元测试的重要性,直到去年看了一些博客和课程,才意识到单元测试的重要性。 - 我的结论是,后端服务单元测试一定要写,而且在时间允许(少摸点鱼)的情况下,一定要尽可能完善。 - 原因: - 正常的逻辑经过通过正常逻辑的单元测试之后,可以避免前端同学人肉验证逻辑的正确性,好处是提高前端同学的对接体验,同时也给提高了后端人员的靠谱属性。 - 特别节省联调时间,前后端开发节奏并不一致,经过详细单元测试之后的逻辑,前端同学和测试测试极少出问题,并且不用打断后端的节奏,被打断的坏情绪会少很多。 - 适应频繁修改造成的不稳定性。看到有人抱怨需求频繁变更,就不想写单元测试了。这只是借口而已,正是因为频繁变动,才更需要。避免改动导致大面积逻辑异常真的可以依靠详细的单元测试。 - 节省后期维护成本,三个月甚至三年之后,你可能需要修改这段代码。如果有完整的单元测试,那绝对是相当舒服的一件事情。 - 最后补上一句,尊重自己,尊重这个行业。不管是自己维护,还是别人,都用心的去编码。即使是屎山,我也希望自己加进去的不是屎。 |
53
charlie21 163 天前
开始写一些框架类代码的时候,才发觉 TDD 的好处
|
54
YSMAN 163 天前
确实国内的环境 变化太快了 单元测试劳动成本 不可小视
|
55
devHang 163 天前 ![]() 写测试的好处在长期维护一个项目的时候才会体现出来。
TDD 是一个好的梳理代码逻辑的办法。 但如果不是自上而下的话,很难推动。 |
![]() |
56
jsjgjbzhang 163 天前
我想知道前端怎么写单元测试
|
57
NoKey 163 天前
不写单元测试的原因,其实主要还是很多项目组或者公司不重视,或者,用人力去解决了。
安排工作量的时候,单元测试根本没有安排,实际工作已经满负荷了。 说白了,不写单元测试都 996 了,项目组或者公司根本没有考虑单元测试的时间。 强行加单元测试,就是 997 了 |
58
micean 163 天前
月经贴吗
写 library 肯定要写单元测试,写业务不会写 |
![]() |
59
aviator 163 天前
做业务的写单测感觉会比写业务代码本身耗时还长
|
![]() |
60
bingoshe 163 天前
1.单元测试时间不够,取决于你的 leader ,你的 leader 当然会跟你说要写,但是不会给你时间
2.996/007 不是因为事情多,而是要对你精神控制 |
![]() |
61
leegradyllljjjj 163 天前
|
![]() |
62
mazai 163 天前
写,必须写,虽然 100%的覆盖率并不代表代码 100%没 bug ,但是可以为我们程序员增加自信呀,比如重构代码,fix bug 不会出现这个 bug 解决了,却影响到其他 feature 的情况。
|
![]() |
63
fulvaz 163 天前
必须写。 能否单测是衡量代码质量的关键因素。
定理:如果我的代码没法测试, 肯定是我在写屎 |
![]() |
64
mazai 163 天前
国内之所以大部分人鄙视单测,第一个原因是不会写单测,第二个原因就是对软件工程文化不够重视。
|
65
exonuclease 163 天前
反正在外企大部分情况下可以测试的代码都需要被覆盖 有一些比较奇怪和 hack 的代码没有 比如魔改 appdomain 的。。。
|
![]() |
67
PainAndLove 163 天前
收藏一下,等有结论了再看
|
![]() |
68
newmlp 163 天前
给钱就写,不给钱还写个毛,不过大部分公司都不给钱
|
![]() |
69
pigf 163 天前
会写 http client 请求
|
![]() |
70
franklinray 163 天前
动不动就是让你 1 、2 个月赶紧做个 demo 上线演示。演示完再给 1 、2 个月完善成产品。代码都写不完,还单元测试。别一说这个问题就是国内没有软件工程文化之类的。如果公司允许我每周就产出一个小函数。我当然愿意单元测试完全覆盖好。说到底还是资本家需要你尽快把代码变现。质量问题就让 QA 操心好了。
|
![]() |
71
linvaux 163 天前
写 ut 的速度赶不上需求变更的速度,写个毛
|
72
erlking 163 天前
通常会把测试时间估进工作量,但如果被恶意压缩工期,那写测试的时间就变成了 buffer……
|
73
wr410 163 天前
能不写就不写,因为根本没时间,扔给测试测去有 bug 再说,反正他们测试案例想的比我周到
|
74
shenyangno1 162 天前
测试中真实调用其他系统的接口、中间件交互(数据库等),算单元测试还是集成测试?一直很迷茫单元测试和集成测试的界限,不同公司的标准好像不太一样,以前写单元测试,涉及跨系统 /中间件的交互,都是 mock 。
|
75
nqlair 162 天前
写,强制要求,没 90%覆盖不给发布
|
![]() |
76
zjyl1994 162 天前
写过单元测试,然后开发流程特别敏捷(天天改功能),单元测试跟不上进度逐渐就荒废了。现在真运行起来 20%通过率都没有
|
77
yedanten 162 天前 via Android
有要求就写 没要求就不写,尤其是敏捷开发模式,今天开发明天上线后天改需求发 v2 版本,这业务都来不及搞定,还写什么测试
|
78
forbreak 162 天前
只有特定的一些开发需要写。写增删改查,业务代码的时候写单元测试,就是写了个寂寞。 今天写完单测,明天需求变了。
|
![]() |
79
helloworld1024 162 天前
天天 curd ,不需要单元测试
|