软件的信心
软件的信心
DiffDay要上线的系统你坐先
心头之问
面对功能强大、日益复杂,给人顶级体验的”过山车“系统,其安全保障也是非常之事,开发者对代码的信心来自哪里?
在给”过山车“添砖加瓦交付的时候,你有如下经历吗?
- 上线也像坐过山车
- 你亲手打造的过山车,自己是否亲身体验过?
- 是否对测试同事说:你们先上去坐坐看,遇到问题再下来找我?
当自己不敢坐,代码要靠测试老师兜底,就说明工作还有待提升空间。反之说明,你作为一个开发者你已经相当优秀了。
单测篇
如何建立对自己代码的信心
借外力
启动前做充分检查:代码评审、让资深人员 (老法师) 帮把关,及时发现问题
练内功
零部件测试(单元测试),保证每一部分在各种场景下都可以正常工作或异常处理得当
对单测的看法
质疑声
常有的声音,尤其在业务变化快的互联网行业:
- 有必要做吗?
- 做到多少合适?
- 现在没做不也挺好吗
实际遇到线上问题需要消耗多少工时?保守估计下面一套下来几个人日是底线值了。
- 找bug,修bug上线
- 修复数据问题
- 复盘闭环规避 (文书工作)
所以常说:发现的越晚,修复耗时越久。编码阶段分钟级、功能测试小时级,发布后就不可控了。【缺陷发现越到交付流程后端,修复成本就越高】
定性来看
写单测抱怨耗时多、可用维护也耗时,但集成测试阶段跟踪调试问题,解决时效被拖长。
单测高覆盖的长周期好处
每次代码改动后可提前发现改动引发的其它关联问题,软件质量更有保障,节省后续同事的精力,拉长周期看效率更高
单测的FIRST原则
看看就好,完全犯不着记
- FAST,快速
- Independent,独立
- Repeatable,可重复
- Self-Validating,自我验证
- Thorough/Timely,彻底、及时
现状及特点
现状
- 从行业特点看:传统行业软件(ERP,CRM等)单测覆盖率至少达到80%以上,互联网行业较低,一般低于50%,大部分没有
- 从软件特点看:用户量较大的软件(工具类,中间件等)基础软件覆盖率相对较高,80%以上,需求变化快的业务类软件较低
- 从开发习惯看:国外开发的软件较高,多数开源软件覆盖率至少60%以上。国内开发者多数未养成习惯
例如我所在的项目环境全量代码单测分支覆盖率普遍看低于30%,质量主要靠测试兜底。这还是在考核变更代码行单测覆盖率的情况下,很多考核流于表面,只看覆盖率,不看通过率。我随处可见运行报告中,用例通过率只有50%,但依然统计生成行覆盖率,而不是中止。另外用例普遍断言宽松,实际并不能达到改动自测的效果。
痛点
-
开发者需投入更多工作量:单测代码行数与应用功能代码至少1:1,复杂应用则更高。随着单测覆盖率的提升,每提升1%,都需要大量的用例。因为后续用例至少有80%甚至90%以上的代码运行路径是重叠的,最坏的情况是增加一个用例,只多了一个覆盖
-
存量代码数量庞大:见上一条
-
单测代码容易失效:单测代码需要持续维护,当业务需求引发的失效要么忽略,要么删除。如此情况下,很难维持一个较高的覆盖率指标。
归根到底,就是成本问题。
这道菜原始原料是 开发者持续投入大量精力(克制牺牲一定要见到实际好处才可持续,但这条维度在任何公司都排不到第一位考核上,它不是直接第一线的结果指标)
自动化解药
静态代码分析
单测自动化以前主流是靠静态代码分析,找出代码隐藏的错误和缺陷,有EvoSuite,Squaretest等
-
此类产品生成的单测行覆盖率一般可达到30%左右,代码越复杂效果越差
-
好处是安装即可用,还支持多种开发平台:idea,eclipse,命令行等
-
缺陷是:生成代码质量不高,覆盖率不高。一些有丰富业务语义的信息,难通过静态分析生成有效的用例代码
大模型
代码大模型也是一条路,但当前阶段没看到大范围铺开,其实飘出的尚未足够革命/实用的味道,在业务语义丰富的方法场景生成效果也不可用
- 每次生成的结果都理解一致无法保证
- 生成的结果需人工修订,断言需大量人工工作,使其可用
- 无法解决系统间集成代码的自测验证用例覆盖
录制回放
将录制数据转化为单元测试用例,获得更加丰富的业务数据,而不是通过一些策略生产数据
此种方案有一个口实弊病:违反了及时性原则,应该在写代码时/提测前完成啊,后录制已经晚了。是的,它不是理论上完美的。
优势
-
存量代码收效大,能快速提升覆盖率
-
新代码,开发本地运行程序自测,录制,而后基于生成的用例,复制,调整快速扩充,也能保证及时性
接口层级用例录制回放
调和这碗意见不一致的羹汤
函数执行逻辑中通常包含 普通函数,外部系统调用两类。其中外部系统调用也含数据库操作。当下微服务时代,系统间的交付变得日益复杂,过度依赖外部服务很难保障用例执行成功。
当前单测框架多采用了mock技术,屏蔽外部服务的依赖,如mockito、powermock、spock等。通过接口录制生成单测,帮开发者回顾找到代码里的bug,通过自动化技术建立单测的信心,软件的信心。
方案优劣势
-
正:用例编码量较少,实现速度快,业务执行路径被测试到,单测覆盖率指标不受影响
-
反:用例失败场景定位较慢
学究派肯定会有疑问?这样做跟集成测试阶段自动化用例有啥区别?
是的,从效果上看是一样的,只不过将运行前移到了开发阶段。
如何做?
每个用例方法对应一个Json/自定义格式文件[非Json反序列稳定性更有优势],记录出入参,全部外部调用的数据。
用例代码和数据均由工具自动生成。大部分代码都是在帮开发者将录制的数据组装Mock对象,这部分工作量在实际开发中是最大的,因此可大幅减轻开发者自己手工编码工作。
当需要手工扩充用例时,只需将用例方法和数据复制一份,再对数据做出调整即可制作出新的用例。
挑战:
- 用例的采样控制,重复用例的识别与剔除。
- 基于动态代理技术实现代码的特殊处理,如mybatis,JSF
- 结构化数据的录制与还原,复杂泛型的还原,复杂对象的序列化和反序列化
- 底层技术如何使接入成本降低,减少对应用的入侵
结语
写单测这部分不是空谈,我们真有在实践,效果不错
参考
- 1.京东云 一台不容错过的Java单元测试代码“永动机” ↩