2020春软件构造Lab4 Debugging, Exception Handling, and Defensi
Debugging, Exception Handling, and Defensi
1 实验目标概述
本次实验重点训练学生面向健壮性和正确性的编程技能,利用错误和异常处理、断言与防御式编程技术、日志/断点等调试技术、黑盒测试编程技术,使程序可在不同的健壮性/正确性需求下能恰当的处理各种例外与错误情况,在出错后可优雅的退出或继续执行,发现错误之后可有效的定位错误并做出修改。
实验针对 Lab 3 中写好的 ADT 代码和基于该 ADT 的三个应用的代码,使用以下技术进行改造,提高其健壮性和正确性:
⚫ 错误处理
⚫ 异常处理
⚫ Assertion 和防御式编程
⚫ 日志
⚫ 调试技术
⚫ 黑盒测试及代码覆盖度
2 实验环境配置
- 在Eclipse Market中搜索SpotBugs静态代码分析工具,完成下载,安装。
在项目上面右键可以看到多出了一个选项卡:SpotBugs,即说明完成插件安装。 - Eclemma
先在eclemma压缩包下载地址:http://sourceforge.net/projects/eclemma/ 下载压缩包,将eclemma压缩包下载下来后解压到Eclipse本地目录的dropins下,重启Eclipse即可。eclemma插件安装成功时,在Eclipse上会出现新的图标 - 在这里给出你的GitHub Lab4仓库的URL地址(Lab4-学号):
3 实验过程
3.1 Error and Exception Handling
3.1.1 处理输入文本中的三类错误
1~6不符合语法;7为元素相同;8为依赖关系不正确
通过ExceptionChain.java相连接
3.1.1.1 EntryNumberFormatException
原因:飞机编号不符合规则
抛出异常方法:检查飞机编号是否符合“前2个字符为大写字母,后4个字符为数字”
3.1.1.2 SerialNumberFormatException
原因:飞机型号不符合规则
抛出异常方法:检查飞机型号是否符合“3位由数字和大写字母组成”
3.1.1.3 SeatNumberException
原因:飞机座位数不符合规则
抛出异常方法:检查飞机座位数是否>0,<=506
3.1.1.4 PlaneAgeFormatException
原因:飞机机龄不符合规则
抛出异常方法:检查飞机机龄是否>0,<=10
同座位数
3.1.1.5 SameAirportException
原因:起飞和到达机场相同引起的错误。
抛出异常方法:对比两个机场字符串是否相等。
3.1.1.6 TimeConflictException
原因:起飞和到达机场时间冲突引起的错误。
抛出异常方法:判断抵达时间是否在起飞时间之前
3.1.1.7 SameEntryException
原因:两班相同航班冲突
抛出异常方法:判断抵达时间是否在起飞时间之前
3.1.1.8 HugeTimeGapException
原因:航班起飞抵达时间跨度太大(超过过一天)
抛出异常方法:判断抵达时间是否在起飞时间之后一天内
3.1.2 处理客户端操作时产生的异常
3.2 Assertion and Defensive Programming
3.2.1 checkRep()检查rep invariants
3.2.1.1 TimeSlot
查看TimeSlot的RI和AF
由此可以设置CheckRep()方法
3.2.1.2 Location
查看Location的RI和AF
由此可以设置CheckRep()方法
3.2.1.3 Resource(Flight)
查看Flight的RI和AF
由此可以设置CheckRep()方法
3.2.2 Assertion/异常机制来保障pre-/post-condition
3.2.2.1 EntryState
判断状态改变前后的合法性,只允许高铁拥有“Blocked”状态
3.2.2.2 PlanningEntry
前置条件为:被分配的资源不能为空。以FlightSchedule为例
后置条件为:更改后的条件不为空
3.2.3 你的代码的防御式策略概述
在客户端到API、API到ADT之间这两种传递过程的起始和完成阶段,都应该进行防御。
3.2.3.1 Client–>API前置条件防御
客户端和API之间,需要基于用户输入参数进行功能控制,因此用户输入的内容正确性决定了API功能实现的正确性。
客户端的输入方法或API的方法起始阶段需要对用户输入进行检查。
例如FlightEntry中需要读入一段数据,为航班分配资源,在方法中对各项参数及逆行了检查,在EntryNumberFormatException中通过ExceptionChain的doBusiness进行抛出异常。
3.2.3.2 Client–>API后置条件防御
在API的操作会对ADT进行影响,若ADT为可变的,则要求Setter()参数正确。检查参数正确可以在API的方法中,也可以在ADT的方法中。
例如在改变计划项之后,会检查该计划项类型是否为可滞留(Blocked)的计划项对象类型。
3.2.3.3
在API的操作会对ADT进行影响,若ADT为可变的,则要求Setter()参数正确。检查参数正确可以在API的方法中,也可以在ADT的方法中。
例如例如API在读入某计划项的资源时,断言判断该ADT的资源是否为空。
3.3 Logging
日志功能的实现调用了 Java 的库 java.util.logging。
1.导入包log4j-1.2.17.jar,目录如下
2.src同级创建并设置log4j.properties
3.在应用类中,只需要加一个全局静态变量,调用已经创建的相关的 logger,再设置无需从控制台输出日志内容即可。以ActivityCalendarApp为例:
3.3.1 异常处理的日志功能
3.3.2 应用层操作的日志功能
应用中使用功能在应用中使用的任何功能,都应该在调用之后马上生成 INFO 调用信息,在功能成功结束后,生成 INFO 成功信息。
3.3.3 日志查询功能
导出日志到log文件
3.4 Testing for Robustness and Correctness
3.4.1 Testing strategy
位置冲突:添加条目使产生冲突;在添加方法时调用方法
资源冲突:添加条目使产生冲突;在添加方法时调用方法
状态冲突:Blocked
3.4.2 测试用例设计
3.4.3 测试运行结果与EclEmma覆盖度报告
ExceptionTest测试运行结果
EclEmma覆盖度测试,以EntryNumberFormatExceptionTest为例
3.5 SpotBugs tool
发现了哪些错误,每种错误代表什么不良的编程习惯
1.
可以创建不同的实例,它们相同,但不以==进行比较,因为它们是不同的对象。通常不应该通过引用进行比较的类的例子有java.lang,Integer,long,float等。
2.
对readLine()的结果值没有进行判空操作就去重新赋值,这样的操作可以会抛出空指针异常。
对代码修改,消除这些错误。
1)
2)判断readLine的结果是否为空
3.6 Debugging
3.6.1 EventManager程序
理解待调试程序的代码思想
该程序要求若干时间区间交集数量的最大值。算法是标记+搜索。将区间的每一个整数点进行标记(用Map),查询是查找Map.values()最大值。
发现并定位错误的过程
键值匹配不恰当,循环条件有问题
你如何修正错误
以最小的键值与所有键值对进行比较,如果最小键值大于其他键值对的键,小于其他键值对的值,active++,最终取最大的active输出
修复之后的测试结果
3.6.2 LowestPrice程序
理解待调试程序的代码思想
该程序想要求在有special offer的情况下最优价格,是贪心算法的一种。首先假设最低代价为所有商品均为零售,然后每次将一个special offer加入“购物车”,更新需求,再用新需求迭代求解,直至求得最低价格
发现并定位错误的过程
测试用例运行后发现错误原因是死循环
你如何修正错误
-
j-1改为j
修复之后的测试结果
3.6.3 FlightClient/Flight/Plane程序
理解待调试程序的代码思想
该程序通过枚举每个航班,尝试安排飞机,确保没有与其他已经分配的航班冲突,最后确认是否能所有同时分配成功。
发现并定位错误的过程
1.While死循环
2. boolean bFeasible一直返回true
3.fStart获取时间进行比较的方法错误
你如何修正错误
-
修复之后的测试结果
Test中无冲突的两架飞机返回true
三架飞机存在冲突返回false
4 实验进度记录
日期 | 时间段 | 计划任务 | 实际完成情况 |
---|---|---|---|
6.3 | 12:30~18:00 | 3.1~3.3 | 3.1完成;3.2开始 |
6.4 | 9:00~11:00; | ||
14:00~18:00 | 3.2~3.3 | 3.2完成;3.4完成;3.3没懂暂时跳过 | |
6.5 | 20:00~ | 3.3+3.5~3.6 | 3.5完成;3.6未完成;3.3不完全 |
6.7 | 13:00~ | 完善3.3 | 完成 |
5 实验过程中遇到的困难与解决途径
-
原Lab3存在较多构造方法的问题,之前写程序也没有标注Testing strategy,省略一些Test,导致Lab4难度加大
请教同学老师,重新编写了Lab3的一些接口
-
log4j的配置和使用
****寻找教程
-
EclEmma覆盖度不高
覆盖率数据只能代表你测试过哪些代码,不能代表是否测试好这些代码,应该设计更多更好的Test
-
使用SpotBugs发现一些bug无法找到解决方法
回顾课程,网上查询,使用JDK API