1、代码错误和检测方法的优劣
分类 | 项目 | 方法 | 说明 |
---|---|---|---|
有特征 | 语法特征错误 | IDE集成的编译器 | 一般不会提交,专门的如Lint |
边界行为特征错误 | 静态检测工具 | 结合代码规则,常见的如:klocwork,Appscan;Sonar,Coverity | |
经验特征错误 | 静态检测工具 | 工具同上 | |
无特征 | 算法错误 | 人工动态测试 人工静态检查 | 一般开发者自测,全部错误的不会到提交阶段。TestNG,Junit;VectorCast,LDRA Testbed TBRun |
部分算法错误 | 人工动态测试 人工静态检查 | 单元测试重点,工具同上 |
常用的人工静态检查方法包括:代码走查、桌面检查、结对编程、同行评审。人工毕竟耗时耗力、效率低、过于依赖个人经验,在代码自动静态检测工具广泛应用后,一般比较常用的也就是同行评审了。
自动检测工具在对有特征的问题处理上很有效,例如:违反编码规则,数组越界、空指针引用、资源泄漏、缓冲区溢出、冗余代码、复杂度过高、代码安全漏洞等;但对于无特征的算法性问题,涉及处理逻辑,在没有实现AI自动识别需求规格书之前,是完全无能为力的。
2、静态测试方法
前面写过一些工具使用内容,一些注意的要点:
- 同行评审:一般结合公司的代码提交流程,和审批、分支管理配合开展。
- 自动静态测试:比较成功的应用,一般都会集成插件到IDE,然后与CI/CD流水线集合。没有条件的,一般还是与代码提交流程配合,要求安装插件,开发者自己在提交前扫描和修改。
3、动态和测试方法
其实目前一般所谓的单元测试框架,都是用来解决这个问题的。目前一般负责一些的工程师都会做单元测试,有的甚至按照测试驱动开发(TDD)的模式来工作,但通常大家一般是针对自己预期的几组数据,对测试实现分支和语句的全覆盖,认为达到要求。单元测试一般做到这个程度,要进一步难度较大,很多时候从性价比角度看也意义不大。但对一些底层和关键模块,需要做得深入一些。
深入单元测试,从策略上来说,测试用例设计需要重点关注:
- 输入数据: 不只是接口的输入数据,还需要关注:全局变量特别是全局静态变量(当然尽量少用) ;调用的类成员变量 ;调用子函数获得的数据;调用子函数改写的数据 ;嵌入式系统中,中断调用改写的数据。这些一般会尽量封装好,但是测试时不注意也会忽略,带来大问题。
- 输出数据:一般都会关注返回值、输出参数,和输入数据一样,也还要关注:改写的成员变量和全局变量;函数运行时的文件更新、数据库更新、消息队列更新等(对环境的改变)。
一般单元测试需要解决的重点是:测试依赖环境的搭建。桩模块和调用Mock模块的构成和编写。目前有些工具会自动分析代码的输入参数,自动构建各种边界值:例如char的自然边界,-128~127。自动产生用例-128,127,0,128,-129来测试。unsigned char没有符号位,因此能表示0~255。对这个自动产生-1,0,255,256来测试。可以减少很大工作量。同时还会根据内部的比较判断条件,a>10,自动产生10,11的测试用例来进行测试。比较典型的如C++test。