1.区分健壮性和正确性
健壮性:系统在不正常输入或不正常外部环境下仍能够表现正常的程度
即使终止执行,也要准确/无歧义的向用户展示全面的错误信息
Robustness principle (Postel’s Law):对自己的代码要保守,对用户的行为要开放
正确性:程序按照spec加以执行的能力,是最重要的质量指标!
正确性倾向于直接报错(error),健壮性则倾向于容错(fault-tolerance)
2.Throwable
Throwable是Error和Exception的父类,用来定义所有可以作为异常被抛出来的类。
Error是编译时错误和系统错误,一般不需要我们关心。Exception又分为RunTimeException(不受检查,能正常编译通过,但是在运行时会暴露出来,比如1/0)和其他Exception(受检查,必须更改通过后才能编译成功,这里涉及到下面的异常处理)。
2.1声明异常与抛出异常
使用throw关键字抛出异常,通常在方法后面加throws Exception。多个异常用逗号隔开。
2…2捕获异常,处理异常。
异常可以被抛出,也可以被捕获。使用try{ }catch(Exception e){e.printStackTrace();(或打印自定义的错误信息、再抛出异常等)}
2.3清理现场、释放资源
进程相关,暂时跳过
2.4自定义异常类
遇到不正确的行为,比如我只让用户选1或者2,结果他输入了666,这个时候就可以throw new Exception("只能选1和2嗷“);
此时程序异常停止,打印错误信息就是”只能选1和2嗷“。
3.防御式编程的基本思路
1.最好的防御就是不要引入bug,如果避免不了,就把它限制在最小的范围内。一个方法内部的Bug,不要扩散到其他方法。
2.尽早失败,才能尽早修复错误。
4断言的作用、应用场合
断言类似于立flag,表示我觉得程序运行到这里必须是这样的。
显然,断言有助于提高正确性,exception有助于提高健壮性。
断言的应用场合:
内部不变量:判断某个局部变量应该满足的条件
表示不变量:checkRep()
控制流不变量:例如,若不想让程序走向switch-case的某个分支,则可以用断言直接在分支上assert false;
方法的前置条件:判断传入参数是否满足前置条件
方法的后置条件:判断结果时候满足后置条件
断言的不正确用法:
//行为包含在断言中
如:assert names.remove(null);执行断言时包含了执行一次remove,应该改为动作先于断言
boolean nullsRemoved = names.remove(null);
assert nullsRemoved;
5.黑盒测试用例的设计
用尽可能少的测试用例尽快运行、尽可能大发现程序错误,检查代码功能,检查程序是否符合规约
5.1等价类划分
举例来说
输入空间为int*int(空间关系,而非算数乘)
5.2边界值分析
bug经常会在各个分区的边界处发生,例如:
在正整数和负整数之间的0
数字类型的最大值和最小值
空集,例如空的字符串,空的列表,空的数组
集合类型中的第一个元素或最后一个元素
结合上面的例子,最终划分为
6测试策略
在测试时应该写下测试策略:
写出测试分区,边界值,特殊值等。
同时在每个小的测试方法前写注解,解释这个测试方法是完成测试策略中的哪一部分
7.Junit测试用例与写法
一个JUnit测试单元是以一个方法(method)写出的,其首部有一个 @Test声明。一个测试单元通常含有对测试的模块进行的一次或多次调用,同时会用断言检查模块的返回值,比如 assertEquals, assertTrue, 和 assertFalse
assertEquals 的参数顺序很重要。它的第一个应该是我们期望的值,通常是一个我们算好的常数,第二个参数就是我们要进行的测试。
8.测试覆盖度
测试效果:路径覆盖(每一个分支的组合路径) > 分支覆盖 > 语句覆盖
测试难度:路径覆盖 > 分支覆盖 > 语句覆盖
EclEmma会将被执行过的代码用绿色标出,没有被执行的代码用红色标出。对于一个分支语句,如果它的一个分支一直没有被执行,那么这个分支判断语句会被标为黄色。