为什么要单元测试

简介: 单元测试是提升研发效能的基石,通过快速、稳定的反馈,显著提高debug效率与代码质量。它降低圈复杂度,助力代码重构,增强模块边界,让系统更易维护和演进。高覆盖单测减少bug、节省排查时间,提升团队对代码变更的信心,长期来看极大提升交付速度与软件可靠性。

提升debug效率
单元测试是软件⼯程极佳的地基,因为它们快速、稳定,并且极⼤地缩⼩了问题范围,提升故障诊断的效率。
● 测试更快:单测没有其他外部依赖,跑的快,可以提供更快的反馈环,更快的发现并修复问题。
● 测试更稳定:同样因为0依赖,单测相⽐于其他类型的测试更稳定,不会受外部其他模块的不兼容变更影响。因此单测也是最能带给开发者信⼼的测试类型。
● 问题更容易定位:单测以最⼩软件单位为边界,出了问题可以缩⼩定位范围。相⽐之下,越是⾦字塔上层的测试类型,定位问题的困难度越⼤。复杂的端到端测试涉及众多的模块,需要⼀⼀排查定位问题。
提升代码质量
代码是写给⼈看的,好的代码应该是易读、易改、易维护的。写单测的过程其实就是吃⾃⼰代码狗粮(dogfood)的过程,从⽤户/研发视⻆去使⽤⾃⼰的代码,帮助我们提升代码质量。
● 好的代码是易测的:业界很早就提出了圈复杂度(Cyclomatic complexity)的概念,⽤来衡量⼀个模块判定结构的复杂程度,其数量上表现为独⽴路径的条数,也可理解为覆盖所有的可能情况最少使⽤的测试⽤例个数。圈复杂度⼤说明程序代码的判断逻辑复杂,可能质量低,且难于测试和维护。因此好的代码⼀定是圈复杂度低的,也是易于测试的。
● 易于迭代演进:没有什么软件是⼀成不变的,好的软件系统应该是易于演进的。单测覆盖⾼的项⽬模块更原⼦化,边界更清晰,修改起来更容易。单测覆盖更全的项⽬重构的⻛险也相对更⼩,相反⼀个没有单测覆盖的复杂项⽬是没⼈敢碰的。
● 更优质的设计:前⾯也提到,好的单测能够提升代码的质量。如果⼀个研发需要给⾃⼰的代码写单测,他就会注重代码的模块化分割,减少过⻓、圈复杂度过⾼的method。下⾯的例⼦就是⼀段没有单测的代码的认知复杂度值(可以理解是圈复杂度的⼀个改良版,从代码是否容易理解的⻆度衡量),超标了⾜⾜三倍。现在回过头来想补单测,脑袋都⼤。
提升总体研发效率
磨⼑不误砍柴⼯,⾼质量、完善的单测可以提升研发质量和效率,加快项⽬总体交付速度。这句话乍⼀看是反常识的,写单测往往⽐写实现逻辑要更耗时,怎么还能提⾼效率?这也是⼤家不写单测最常⻅的理由:“项⽬赶进度,来不及写单测”。如果我们的项⽬⽣命周期是以⽉计算的,写个原型很快就下线了,那写单测的确ROI不⾼。但阿⾥有很多to B的业务,提供给⽤户的能⼒都是以年计算⽣命周期的,⾼质量代码的ROI随着时间推移会越来越⾼,具体体现在以下⽅⾯:
● 减少debug时间:上⾯提到种种提升debug效率的原因,这⾥不再重复。⼀⽅⾯更⾼的单测覆盖可以节省debug所花费的时间,另⼀⽅⾯有充⾜测试覆盖的项⽬本身bug数量就会更少。举个现实中的例⼦:某团队由于历史上⽋的种种债务,基本全靠端到端测试,毫⽆单元测试覆盖。造成的后果也⾮常严重,团队oncall的同学 > 50%的时间都是在修复各种奇怪的bug,没法投⼊宝贵的精⼒到架构升级等⻓期更重要的项⽬上。
● 增加代码变更的信⼼:前⾯提到没有测试覆盖的代码没⼈敢碰,有充⾜单测覆盖的代码可以显著提升改造代码的信⼼和意愿。

相关文章
|
1天前
|
Java
ArrayList扩容机制
ArrayList初始化容量为0,添加第一个元素时触发扩容,minCapacity设为10,执行grow(),容量从0扩至10。后续添加元素至第10个时均不扩容。添加第11个时,minCapacity为11,大于当前容量10,再次调用grow(),新容量为15。grow()通过比较minCapacity与旧容量的1.5倍决定新容量,不超过最大值。注意:length用于数组,length()用于字符串,size()用于集合。
|
1天前
|
缓存 数据建模 文件存储
EFC&CTO:缓存引发数据不一致问题排查与深度解析
EFC客户端更新缓存架构后,首次适配NAS场景CTO测试即出现data mismatch。排查发现并非缓存版本号导致的旧数据读取问题,而是文件系统数据被破坏——正常字符被替换为空字符,且错误集中于同一4K页内。初步判断为缓存引入导致pagecache被异常写坏,脏页回刷污染了远端数据。空字符来源及具体触发操作待进一步分析。
|
1天前
|
SQL 监控 Java
如何做好SQL质量监控
在 SLS 中,用户可以通过 SQL 对日志数据(结构化、半结构化、无结构化)进行查询和分析。随着用户对 SQL 使用程度的不断加深,越来越多的用户希望了解自己使用 SQL 分析时的服务反馈(如请求量、成功率、数据量等等),以便对数据和分析行为进行精细管理或优化治理。
|
1天前
|
测试技术 Nacos 开发者
从Google线上故障,谈灰度发布的重要性2
业务配置灰度可通过主流配置中心实现,如Nacos支持IP和标签灰度,可扩展SPI定制策略;Apollo仅支持IP灰度,二者均可二次开发。复杂场景可基于Nacos标签扩展或自研方案,多数场景推荐使用Nacos满足需求。
|
1天前
|
测试技术 API 定位技术
从Google线上故障,谈灰度发布的重要性
2025年6月12日,Google Cloud因新功能未充分测试且未灰度发布,导致Service Control系统出现空指针异常,引发全球大规模服务中断,持续超7小时。故障暴露了配置管理与错误处理的严重缺陷,凸显配置灰度发布在核心系统中的关键作用。
|
1天前
|
消息中间件 Arthas NoSQL
RocketMQ:底层Netty频繁OS OOM
JVM使用jemalloc分配native内存,排查发现无明显泄漏。通过pmap、gdb分析及Arthas查看Netty堆外内存占用,定位到RocketMQ客户端因Netty直接内存分配导致内存超1G。调整MaxDirectMemorySize引发消息积压,最终确认问题源于Netty内存管理机制。短期方案为压缩Java堆,腾出堆外空间保障MQ可用性。
|
1天前
|
运维 开发工具 git
生产环境缺陷管理
软件开发中,bug难以避免,而多分支协作与异步沟通易致问题重复发生。百人团队协同成本剧增,人为疏漏不可避免。唯有通过自动化工具实现bug全流程管控,才能从“依赖不犯错”转向“无法犯错”,保障发布质量。
|
1天前
|
运维 监控 NoSQL
Redis:内存陡增100%深度复盘
遵循Redis命令与运维规范,避免使用KEYS、Lua脚本等高风险操作,推荐SCAN、管道、扩展数据结构提升性能。合理配置监控、慢日志、Top Key分析,及时处理大Key、热Key及计划运维事件,保障实例稳定高效运行。
|
1天前
|
存储 运维 NoSQL
Redis:内存陡增100%深度复盘
本文分析了Redis在11:22:02因缓冲区激增导致不可用的事故。根源在于流出带宽自然增长至96MB/s,触发输出缓冲区暴涨,连接断开后请求涌向DB,大量大KEY写入又引发输入缓冲区激增,最终占用全部内存,阻塞主线程。事故暴露了网络与存储资源双重瓶颈,凸显遵循开发运维规范的重要性,如合理设计Key、控制命令使用、优化SDK配置等,以避免性能边界被突破。
|
1天前
|
存储 NoSQL 安全
Redis:内存陡增100%深度复盘
缓冲区用于暂存数据,防止处理速度跟不上发送速度导致丢数据。Redis通过输入/输出缓冲区管理命令与响应,但输出缓冲区在Pub/Sub模式下可能剧增,理论最大占用达9.375GB,远超实例内存(如2GB),导致SET/GET失败,系统无法正常工作。

热门文章

最新文章