1 异常
异常:程序执行中的非正常事件,导致程序无法再按预想的流程执行
Exceptions将错误信 息传递给上层调用者,并报告“案发现场”的信息 通过 throws 退出异常
-
运行时异常:由程序员在代码里处理不当造成
可能有类型转换异常,越界异常,空指针异常 -
其他异常:由外部原因造成
throws 声明“本方法可能会抛出XX异常
throw 抛出XX异常
(try, catch, finally) 捕获并处理XX异常
unchecked 异常 指无效状态异常:方法被调用时,程序处于不能被该方法调用的状态
当要决定是采用checked exception还是unchecked exception的时候,问一个问题:“如果这种异常一旦抛出,client会做 怎样的补救?”
- 如果客户端可以通过其他的方法恢复异常,那么采用 checked exception
- 如果客户端对出现的这种异常无能为力,那么采用unchecked exception;
总结:
- 方法要在定义和spec中明确声明所抛出的全部checked exception
- 没有声明所有抛出的 checked异常,编译会出错
- Unchecked异常和Error可以不用处理
- 如果子类型中override了父类型中 的函数,那么子类型中方法抛出的异常不能比父类型抛出的异常类型 更宽泛
- 子类型方法可以抛出更具体的异 常,也可以不抛出任何异常
- 如果父类型的方法未抛出 异常,那么子类型的方法也不能抛出异常。
2 断言与防御式编程
断言:在开发阶段的代码中嵌入,检验某些“假设”是否 成立。若成立,表明程序运行正常,否则表明存在错误。
断言即是对代码中程序员所做假设的文档化,也不会影响运行时性能 (在实际使用时,assertion可以被disabled)
断言一旦false,程序 就停止执行。
外部失败要 使用Exception机制去处理。
断言非常影响运行时的性能
- 如果参数来 自于外部(不受自己控制),使用异常处理
- 如果来自于自己 所写的其他代码,可以使用断 言来帮助发现错误
3 代码调试
从最小的测试用例集开始复现错误
软件版本
软件的运行环境
输入数据
在程序内部各部分展示程序执行时的动态信息,比使用静态的dump 分析更有效。
4 日志
通过设定日志级别来确 定要log哪些信息
log结果可被多种渠道加 以处理,可通过设定条件进行过滤,并输出为多种格式
可使用层次化的多个日志记录器
5 测试
用等价划分和边界值分析方法为模块设计测试用例
可用工具 度量一组测试用例对代码的“覆盖度”
- 等价类划分
- 边界值分析
确保程序正确性/健壮性的最普遍的手段:测试
1 设计测试用例 2 用JUnit写测试程序 3 自动化测试过程
- 先写specification
- 再写符合spec的测试用例
- 写代码、执行测试、有问题再改、再执行测试用例,直到通过它
6 等价类划分
基于等价类划分的测试:将被测函数的输入域划分为等价类, 从等价类中导出测试用例。
针对每个输 入数据需要满足的约束条件,划分等价类
等价类应该满足:对称、传递、自反
7 边界值分析
由于大量的错误发生在输入域的“边 界”而非中央,边界值分析方法是对等价类划分方法的补充
多个划分维度上的多个取值,要组合起来,每个组合都要有一个用例
- 笛卡尔积:全覆盖
- 覆盖每个取值:最少1次即可
8 黑盒和白盒测试
黑盒测试完 全从函数spec导出测试用例,不考虑函数内部实现
白盒测试要考虑内部实现细节
- 根据程序执行路径设计测试用例
- 白盒测试一般较早执行
9 代码覆盖度
代码覆盖度:已有的测试用例有多大程度覆盖了被测程序
代码覆盖度越低,测试越不充分 但要做到很高的代码覆盖度,需要更多的测试用例,测试代价高
测试效果:路径覆盖>分支覆盖>语句覆盖
测试难度:路径覆盖>分支覆 盖>语句覆盖
适用EclEmma工具来测试代码覆盖度
测试策略(根据什么来选择测试用例)非常重要,需要在程序中显式记录下来