软件构造-数据处理的软件构造
目录
本章目标:
- 把算式和习题从程序变量的值转化为 可共享的、持久性的文件数据,学习文件的产生、 存储和读取操作,学习一个特殊的文本文件格式 CSV。
- 编程方面,学习表驱动编程模式和防御性编程。
- 测试方面,学习白盒测试的基本技术,继续学习 JUnit 的其他测试方法。
数据及其持久性
持久数据:
保存在程序之外(如文件、网络)的数据在
在实现数据持久化之前,需要考虑以下几个方面的问题:
- 数据的持久性和使用频次
- 生产和访问数据的难易程度
- 共享与传输
- 数据的量及管理
- 数据的操作方式
文件的输入输出流
流:
流表示任意输入的源或输出的目的地。流即传输数据的管 道,让外部输入设备或存储器上的数据流入内存,让程序中的数据 流出。
数据序列化
如何实现读写
要把对象转换成字符串,在Java 中类似toString。
首先要把具有结构的数据元素分 解,转换成字符串,然后用特殊分隔符隔离。
每 个数据对象还要再以分隔符隔离。
csv文件
CSV文件由任意数目的记录组成,记录之间以某种换行符分隔;每条记录由 字段组成,字段间的分隔符是其他字符或字符串,最常见的是逗号或制表符。
纯文本,使用某个字符集,如ASCII、Unicode、EBCDIC 或GB2312;
- 由记录组成(典型的是每行一条记录);
- 每条记录被分隔符分隔为字段(典型分隔符有逗号、分 号或制表符;有时分隔符可以包括可选的空格);
- 每条记录都有同样的字段序列。
编写健壮的程序
防御性编程
防御编程的基本思想是:程序员要预计其他程序员 的过错、无效的输入、甚至有害的数据及使用者的 过失,即使这种事情罕见,也要采取适当措施保护 自己的程序。
错误处理的一些建议:
- 继续运行程序、返回中性无害的数据。
- 用最接近的有效数据替换无效数据。
- 在日志中记录警告信息并继续运行程序。
- 调用错误处理程序或对象。
- 屏幕显示错误信息。
- 尽可能在局部处理错误。
- 返回一个错误编码,让特定程序处理这个错误。
断言
使用断言的一些建议:
- 对预计出现的条件使用错误处理,对不应当出现的条件使 用断言。错误处理用于检查不合理的输入数据;
- 断言则用 于检查代码中的错误。
- 避免在断言中放置可执行的代码。因为关闭断言后,编译 器可能会删除这些代码。
- 用断言来记录和验证前置条件和后置条件。
- 健壮性要求高的程序使用断言和错误处理。
字符串处理与正则表达式
java中String对正则表达式的部分使用
• boolean matches (String regxep)、
• void replaceAll (String regxep, String replacement)
• String [] split(String regxep)
它们的 作用分别是匹配、替换全部匹配内容、分割。参数 都包含了正则表达式regxep。
基于程序结构的测试
语句覆盖测试
设计测试,检测程序的每条语句是否都能执 行。如果一个测试用例没有使所有的语句都 得到执行,就增加测试,试图增加执行的语 句数量,直至所有语句都能执行。否则,要 么测试用例不够,不能使所有语句都执行; 要么程序有缺陷,出现了不可能执行的语句。 把这种测试称为语句覆盖测试
语句覆盖不可靠
即使是 100%的语句覆盖测 试也不能保证程序正确无误。 语句覆盖是最容易实现、也 是最弱的覆盖准则
程序控制流图
(1)节点:圆圈表示一条可执行的基本语句,可以增加标记, 如语句号或节点顺序号;
(2)控制线或弧:用带箭头的有向线表示连结的两个语句的 执行顺序;
(3)程序执行(控制流)的分叉或交汇处,可以用节点表示;
(4)每个函数或程序都有唯一的开始和结束节点;
(5)不含执行程序不可达到的语句或不能使程序停止的语句;
(6)控制线必须连接两个节点,开始节点和结束节点除外。
逻辑覆盖测试
判定覆盖
设计测试用例使得程序的每个判断分支都至少经历一次。 由于一个判定往往代表着程序的一个分支, 所以判定覆盖也称分支覆盖
条件覆盖
设计测试用例,使得程序 中的每个简单布尔条件的所有可能的值都至少 满足一次。
路径覆盖测试
按照等价类的思路,我们希望测试的每条路径都有所不同, 但又尽量包含可能多的路径,通常采用基本路径覆盖法
基本路径是指,和其他基本路径相比,至 少引入一个节点或一个新的控制线的路径
圈复杂度=边数-节点数+2 ( 圈复杂度越高表示程序的逻辑复杂度越高 )
圈复杂数超过了(5 )就要采用基本 路径覆盖的测试。
找出一条基本路径
(1)首先,CFG 的开始节点入栈;
(2)从栈顶按照CFG 连线,选择下一个节点:如果一个节点的出度 outDegree大于0,选择之前没有选择过的后继节点,outDegree−1;
(3)重复(2)直至栈顶是CFG 的结束节点。从栈内输出节点,其逆序就是 一条基本路径;
(4)寻找下一条基本路径,从栈顶逐个退出节点:如果遇到一个节点的出 度大于1 且当前outDegree 大于0,则重复步骤(2)~(4);如果退出开始 节点,则查找结束