软件构造总结(7)

7.正确性的软件构造

7.1 健壮性和正确性

健壮性:系统在不正常输入或不正常外部环境下仍能够表现正常的程度。(对自己的代码要保守,对用户的行为要开放)实现方法:封闭实现细节,限定用户的恶意行为。
正确性:程序按照spec加以执行的能力,是最重要的质量指标。
正确性倾向于直接报错(error),健壮性则倾向于容错(fault-tolerance)
对外的接口,倾向于健壮;对内的实现,倾向于正确。
可靠性=健壮性+正确性

7.1.1衡量正确性和健壮性

Mean time between failures (MTBF,平均失效间隔时间)

7.2 错误与异常处理

Java中的错误与异常机制,异常的处理

7.2.1 Java中的错误和异常

内部错误:程序员通常无能为力,一旦发生,想办法让程序优雅的结束
异常:你自己程序导致的问题,可以捕获、可以处理。
错误的种类:用户输入错误、设备错误、物理限制

7.2.2 异常的处理

异常:程序执行中的非正常事件,程序无法再按预想的流程执行

  • 异常的分类
    异常被定义为一种可抛出的类型
  • RuntimeException
    运行时异常,是程序源代码中引入的故障所造成的
  • checked和unchecked的异常
    unchecked异常:在代码中就没有catch也没有throw,编译的时候会通过,但是运行时如果出错会直接停止。编译器可帮助检查你的程序是否已抛出或处理了可能的异常
    checked异常:被throw或catch的异常。
    如果客户端可以通过其他的方法恢复异常,那么采用checked exception
    如果客户端对出现的这种异常无能为力,那么采用unchecked exception
    在编程的时候尽量使用unchecked异常,这样方便确认出错的位置。
  • 异常处理
    可以通过throw来处理异常,但是如果最终的调用者没有handler来处理被抛出的checked exception,程序就终止执行。
    程序员必须在方法的spec中明确写清本方法会抛出的所有checked exception,以便于调用该方法的client加以处理。
    如果子类型中override了父类型中的函数,那么子类型中方法抛出的异常不能比父类型抛出的异常类型更宽泛。
    子类型方法可以抛出更具体的异常,也可以不抛出任何异常。
    如果父类型的方法未抛出异常,那么子类型的方法也不能抛出异常。
  • 异常的定义
    定义一个checked异常:(重写四个方法即可,基本都是super)
    在这里插入图片描述
    自定义一个unchecked异常:(相较于checked内容更加简单)
    在这里插入图片描述
  • 捕获异常
    使用try-catch捕获异常。如果选择了throw那么即是将异常传递给调用者进行处理。
  • 重新抛出和链接异常
    catch操作后既可以用来处理异常,也可以用来改变异常的类型,方便用户获取信息。
    finally操作:无论异常有没有被捕获到,都会执行。用来关闭或清除之前申请的资源。
  • 调用栈分析
    将方法之间的调用关系,一层一层的输出。后调用的先输出。

7.3 断言与防御式编程

检查前置条件是防御式编程的典型形式

7.3.1 断言

断言在开发阶段的代码中嵌入,用于检验某些假设是否成立。
在检查表示不变量、方法的前置条件、后置条件的时候需要使用断言。由于在程序投入使用时断言将不再被执行,所以,应该避免断言语句执行了某一个关键代码。
内部错误使用断言,外部错误使用异常机制处理。
断言提升了正确性,异常机制提升了健壮性。

7.3.2 防御式编程

对来自外部的数据源要仔细检查,例如:文件、网络数据、用户输入等。对每个函数的输入参数合法性要做仔细检查,并决定如何处理非法输入。
类的public方法接收到的外部数据都应被认为是dirty的,需要处理干净再传递到private方法——隔离舱。

  • Debug过程注意的
    使用具有进攻性的编程方式,注意删除Debug过程中的代码。

7.4 Debug专题

7.4.1 使用Log调试

Java自带的log库:java.util.logging。
通过设定日志级别来确定要log哪些信息、log结果可被多种渠道加以处理,可通过设定条件进行过滤,并输出为多种格式、可使用层次化的多个日志记录器。
缺省:输出到控制台。除了ConsoleHandler,还可以设定其他的handlers:

StreamHandler、FileHandler、SocketHandler、MemoryHandler

7.5 软件测试与测试优先的编程

重点:测试用例,单元测试,黑盒测试(等价类划分,边界值分析)

7.5.1 软件测试

提高软件质量,提高代码的正确度。

  • 测试等级
    单元测试、集成测试、系统测试
  • 黑盒测试
    对程序外部外部表现出来的行为进行测试
7.5.2 测试用例(Test Case)

测试用例:输入+执行条件+期望结果

7.5.3 测试优先的编程

先写spec,再写符合spec的测试用例。写测试用例,就是理解、修正、完善spec设计的过程。
spec描述了方法预期的输入和输出。先写测试会节省大量时间。

7.5.4 单元测试

针对软件的最小单元模型开展测试,隔离各个模块,容易定位错误和调试。

7.5.5 使用JUnit自动生成单元测试

assertTrue,assertEqual是十分常用的。
测试的文件路径应该和源文件的文件路径一致。

7.5.6 黑盒测试

用于检查代码的功能,不关心内部实现细节。

  • 等价类划分
    基于等价类划分的测试:将被测函数的输入域划分为等价类,从等价类中导出测试用例。
    针对每个输入数据需要满足的约束条件,划分等价类。基于假设:相似的输入会产生相似的行为。故可以选择等价类中的一个代表进行测试即可。
    例1:
    高精度乘法,可以将两个数中的任何一个数分为以下七类:大负数,小负数,-1,0,1,小正数,大正数
    因此两个数有如下的测试组合:
    在这里插入图片描述
    例2:
    取最大值的方法,划分为a>b a<b a=b三种等价类。
  • 在分区的时候包含边界
    大量的错误发生在边界上而不是取值范围的中间。同样的边界的两侧也需要考虑。
    在例2中,可以添加上整数的最大值和最小值进行比较。
7.5.7 测试覆盖度

代码覆盖度:已有的测试用例有多大程度覆盖了被测程序
测试效果:路径覆盖>分支覆盖>语句覆盖
测试难度:路径覆盖>分支覆盖>语句覆盖
路径覆盖:每一个分支全部测试一遍。但是路径量巨大,难以覆盖全面。

7.5.8 测试策略的文档

测试策略(根据什么来选择测试用例)非常重要,需要在程序中显式记录下来 。在这里插入图片描述
这是一个反转字符串方法的测试,可以看到:
将字符串长度分为0,1,>1三种情况
将开始的位置分为0,1,>1但是<字符串长度,字符串长度-1(最后一位)和等于字符串长度(超了一位)、
被反转的部分字符串的长度为:0,1,奇数,偶数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值