代码测试篇
代码测试篇
- 测试人员应该具备的代码级测试基础知识:代码级测试技术入门、方法论、用例设计、覆盖率衡量、典型难点、解决思路等
- 代码级错误
- 有特征错误:语法特征错误、边界行为错误、经验特征错误
- 无特征错误:算法错误、部分算法错误
常见代码错误类型
- 语法特征错误
- 从语法上就能发现的错误
- e.g. 数组越界
- 边界行为特征错误
- 在执行过程中发生异常、崩溃或超时
- e.g. a/b b=0时就会发生边界错误
- 经验特征错误
- 根据过往经验发生的错误
- e.g. if(a=b) 本来想做逻辑比较,结果写成了赋值
- 算法错误
- 代码的预期计算结果与实际结果不一致
- 部分算法错误
- 只在特定的输入情况下,算法不能准确的完成业务功能
代码测试常用的方法
静态方法
- 不用实际执行代码而发现的代码缺陷
- 人工静态方法
- 开发人员代码走查:开发自己查自己的代码
- 结对编程:敏捷软件开发下的方法,两个人一起,一个“驾驶员”,一个“观察员”,通常会定期更换两个角色
- 同行评审:提交的代码在merge到master之前,必须由同级别或更高阶别的同事review之后才能merge,比如Github里提交PR,PR被统一才能merge
- 自动静态方法
- 通过词法分析、语法分析、控制流分析等技术,并结合预定义和自定义代码规则,对程序进行静态扫描发现的语法错误、潜在语义错误以及部分动态错误一种代码分析错误
- 工具:Sonar、Converity都支持多种语言
动态方法
- 通过实际执行代码发现的代码缺陷
- 人工动态方法
- 主要的测试手段
- 通过输入、执行代码、测试输出
- 善于发现算法错误和部分算法错误
- 自动静态方法
- 又称自动边界测试方法
- 基于代码自动生成边界测试用例并执行,以捕获潜在的异常、崩溃和超时
动态测试方法
单元测试的3个主要难点
- 输入参数的复杂性
- 被测函数的输入参数
1
2
3
4//输入数据:a和b的不同取值以及组合
int someFunc(int a,int b){
...
} - 被测函数内部需要读取全局静态变量(包括类成员变量)
- 那么这个变量也是被测函数的输入参数
1
2
3
4
5
6
7
8
9//输入数据:a、b、someGlocalVariable的不同取值以及组合
Boolean someGlocalVariable = true;
void func_SUT(int a){
if(someGlocalVariable){
funcA();
}else{
funcB();
}
} - 函数内部调用子函数获得数据
1
2
3
4
5
6
7
8
9//func_SUT()传了a,其实内部只是FuncX用了一下,这种情况属于间接传递参数,一般直接对FuncX(a)打桩
void func_SUT(int a){
Boolean toggle = FuncX(a);
if(toggle == true){
funcA();
}else{
funcB();
}
}
- 预期输出的复杂性
- 被测函数的返回值
1
2
3int add(int a,int b){
return a+b;
} - 被测函数改写了成员变量和全局变量,那么这些变量也要作为assert的对象
- 被测函数中进行的文件更新、数据库更新、消息队列更新
- 在实际单元测试实践中,因为测试解耦的需要,一般不会真正做这些操作,而是借助Mock对象的断言来验证是否发起了相关操作
- 关联依赖的代码不可用
- 使用桩函数来代替被依赖的不可用的函数