《软件构造》 第七章 软件构造的健壮性

》》健壮性和正确性

健壮性:系统在不正常输入或不正常外部环境下仍能够表现正常的程度,处理未期望的行为和错误终止。即使终止执行,也要准确/无歧义的向用户展示全面的错误信息。

正确性:按照spec加以执行的能力。用户输入错误时,直接结束

一般来说,对外的接口,倾向于健壮性;对内部的实现,倾向于正确性

测量健壮性和正确性的方法:

——外部观察角度:Mean time between failures (MTBF,平均失效间隔时间):描述了可修复系统的两次故障之间的预期时间,而平均故障时间(MTTF)表示不可修复系统的预期故障时间。

——内部观察角度:残余缺陷率:每千行代码中遗留的bug的数量

》》错误和异常处理 

Throwable 类是 Java 语言中所有错误或异常的父类。继承的类:extends Object。实现的接口:implements Serializable。


《软件构造》 第七章 软件构造的健壮性_第1张图片

内部错误(error):程序员通常无能为力,一旦发生,想办法让程序优雅的结束

Error的类型:

——用户输入错误

例如:用户要求连接到语法错误的URL,网络层会投诉。

——设备错误

例如:硬件并不总是做你想做的。输出器被关闭

——物理限制

例如:磁盘可能被填满,可能耗尽了可用内存

异常(Exception):你自己程序导致的问题,可以捕获、可以处理。使我们可以处理的东西,可以有异常处理程序,若找不到异常处理程序那么整个系统就完全退出。

除了Runtime异常,其他的异常都是checked。checked的异常如果可能存在,必须要做出异常处理,否则程序就会报错

——Declaring exceptions (throws) 声明“本方法可能会发生XX异常”,写在方法一开始,有throws没有try/catch

——Throwing an exception (throw) 抛出XX异常

——Catching an exception (try, catch, finally) 捕获并处理XX异常

《软件构造》 第七章 软件构造的健壮性_第2张图片

checked异常的处理机制:

——抛出:声明是throws,抛出时throw    

——捕获(try/catch):try出现异常,忽略后面代码直接进入catch;无异常不进入catch;若catch中没有匹配的异常处理,程序退出;若子类重写了父类方法,父类方法没有抛出异常,子类应自己处理全部异常而不再传播;子类从父类继承的方法不能增加或更改异常

——处理:不能代替简单的测试,尽量苛刻、不过分细化、将正常处理与异常处理分开、利用好层次结构、早抛出晚捕获、避免不必要的检查

——清理现场、释放资源(finally):finally中语句不论有无异常都执行,一定会执行除了finally语句块中有异常、或者程序所在线程死亡、或者程序提前exit结束。

unchecked异常:不需要try-catch,你无法解决

关于他们两种:Checked exception应该让客户端从中得到丰富的信息。 要想让代码更加易读,倾向于用unchecked exception来处理程序中的错误

《软件构造》 第七章 软件构造的健壮性_第3张图片

一般自定义异常都是extends Exception,如果unchecked的话继承RuntimeException

》》断言和防御式编程

断言:在开发阶段的代码中嵌入,检验某些“假设”是否成立。若成立,表明程序运行正常,否则表明存在错误(在实际运行时不会影响性能)

例子:

《软件构造》 第七章 软件构造的健壮性_第4张图片

断言主要用来处理绝对不可能发生的情况,比如指针为空 、子程序开始执行(结束)时,文件或流处于打开(关闭)状态子程序开始执行(结束)时,文件或流的读写位置处于开头(结尾)

》》Debug

识别程序的错误,然后消除错误。

——Debug是测试的后续步骤:测试发现问题,debug消除问题;当防御式编程和测试都无法挡住bug时,我们就必须进行debug了;

——Debug的目的:寻求错误的根源并消除它;(Debug占用了大量的时间)

》》Test

发现程序中的错误 提高程序正确性的信心。

程序正确确认的基本方法:

1.形式化推理

2.代码评审

3.测试

静态测试静态测试通常是隐式的,作为校对,加上编程工具/文本编辑器检查源代码结构或编译器(预编译器)检查语法和数据流作为静态程序分析。

动态测试:描述了代码的动态行为的测试,它实际上是用一组给定的测试用例来执行编程的代码。

白盒测试:对程序内部代码的测试

黑盒测试:对程序外部表现出来行为的测试

——等价划分 :将程序可能的输入进行分类划分为不同集合包括不合法数据,基于等价类划分的测试:将被测函数的输入域划分为等价类,从等价类中导出测试用例。(比如正数,0,负数)

等价类划分可有两种不同的情况:有效等价类和无效等价类。

若一组对象自反、对称、传递,则为等价类

可产生相似结果的输入集合中的一个可代替整个集合

同理,对输出也可以划分等价类

极端:每个分区只有一个测试用例,覆盖所有分区

——边界值分析方法  :边界值分析法是对输入输出的边界值进行测试一种黑盒测试方法,是对等价类分析法的补充。

错误通常隐藏在边界中,如一位偏移、边界值需单独处理等

找到有效数据和无效数据的分界点(最大值、最小值),对该分界点以及两边的值分别单独进行测试。

等价类划分法可以挑选等价类范围内任意一个数据作为代表,而边界值分析法要求每个边界值都要作为测试条件。

》》以注释的方式编写测试策略

例子:

《软件构造》 第七章 软件构造的健壮性_第5张图片

》》JUnit测试用例写法:Junit单元测试是依据 注释中@Test 之前的方法编写的JUnit测试经常调用多次方法,使用 assertEqual || assertTrue || assertFalse 来检查结果@Before:准备测试、完成初始化,每个测试方法前执行一次@After:清理现场,每个测试方法后执行一次

例子:

public class Calculator {
    public int evaluate(String expression) {
        int sum = 0;
        for (String summand: expression.split("\\+"))
            sum += Integer.valueOf(summand);
        return sum;
    }
}
---------------------------------------
import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class CalculatorTest {
@Test
public void evaluatesExpression() {
        Calculator calculator = new Calculator();
        int sum = calculator.evaluate("1+2+3");
        assertEquals(6, sum);
    }
}




你可能感兴趣的:(《软件构造》 第七章 软件构造的健壮性)