软件构造lab4总结

实验目标概述

本次实验重点训练学生面向健壮性和正确性的编程技能,利用错误和异常处 理、断言与防御式编程技术、日志/断点等调试技术、黑盒测试编程技术,使程序 可在不同的健壮性/正确性需求下能恰当的处理各种例外与错误情况,在出错后 可优雅的退出或继续执行,发现错误之后可有效的定位错误并做出修改。
实验针对 Lab 3 中写好的 ADT 代码和基于该 ADT 的三个应用的代码,使用 以下技术进行改造,提高其健壮性和正确性:
错误处理
异常处理
Assertion 和防御式编程
日志
调试技术
黑盒测试及代码覆盖度

实验环境配置

在Eclipse中找到Marketplace下载SpotBugs安装
在这里插入图片描述

实验过程

3.1 Error and Exception Handling

3.1.1处理输入文本中的三类错误

3.1.1.1输入文件中存在不符合语法规则的语句
  1. IllegalPatternException
    不符合规范模式的输入文件,如行数不对,Plane打错字符等,使其无法匹配到正则表达式的异常
Pattern pattern = Pattern.compile(
     "Flight:(.*?),(.*?)\n\\{\nDepartureAirport:(.*?)\nArrivalAirport:(.*?)\nDepatureTime:(.*?)\nArrivalTime:(.*?)\nPlane:(.*?)\n\\{\nType:(.*?)\nSeats:(.*?)\nAge:(.*?)\n\\}\n\\}\n");
   Matcher matcher = pattern.matcher(info);
   if (!matcher.find())
    throw new IllegalPatternException("输入文件不符合规范模式");
  1. IllegalDateException
    首行的日期不符合yyyy-MM-dd的模式,抛出该异常
Pattern pattern2 = Pattern.compile("((19|20)[0-9]{2})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])");
   Matcher matcher2 = pattern2.matcher(FlightDate);
   if (!matcher2.find())
    throw new IllegalDateException("Date " + FlightDate + "不符合规范模式");
  1. IllegalFlightNumberException
    不合法的航班号,即不符合lab3中规定的两个英文字母和四个数字的要求
if (Character.isUpperCase(Number.charAt(0)) && Character.isUpperCase(Number.charAt(1))) {
   for (int i = 2; i < Number.length(); i++) {
    if (!Character.isDigit(Number.charAt(i)))
     throw new IllegalFlightNumberException("FlightNumber:" + Number + "不符合规范模式");
   }
   if (Number.length() > 6)
    throw new IllegalFlightNumberException("FlightNumber " + Number + "不符合规范模式");
  } else
   throw new IllegalFlightNumberException("FlightNumber " + Number + "不符合规范模式");
  1. IllegalPlaneNumberException
    不合法的飞机编号,不符合第一位为N或B,后面为四位数字的规定
if (Number.charAt(0) == 'N' || Number.charAt(0) == 'B') {
   for (int i = 1; i < Number.length(); i++) {
    if (!Character.isDigit(Number.charAt(i)))
     throw new IllegalPlaneNumberException("PlaneNumber " + Number + "不符合规范模式");
   }
   if (Number.length() > 5)
    throw new IllegalPlaneNumberException("PlaneNumber " + Number + "不符合规范模式");
  } else
   throw new IllegalPlaneNumberException("PlaneNumber " + Number + "不符合规范模式");
  1. IllegalPlaneSeatException
    不合法的飞机座位数,即超过了600或小于50时抛出异常
if (seats > 600 || seats < 50)
     throw new IllegalPlaneSeatException("PlaneSeats " + seats + "不符合规范模式");
  1. IllegalPlaneTypeException
    Type只有数字和字母组成,否则抛出该异常
String regex = "^[a-z0-9A-Z]+$";
    if (!type.matches(regex))
     throw new IllegalPlaneTypeException("PlaneType " + type + "不符合规范模式");
  1. IllegalPlaneAgeExcepion
    Age只能是整数或一位小数,否则抛出该异常
String regex2 = "^[+]?([0-9]+(.[0-9]{1})?)$";
    String regex3 = "^[0-9]*[1-9][0-9]*$";
    if (age >= 0 && age <= 30) {
     if (!strAge.matches(regex2) && !strAge.matches(regex3))
      throw new IllegalPlaneAgeException("PlaneAge " + age + "不符合规范模式");
    } else {
     throw new IllegalPlaneAgeException("PlaneAge " + age + "不符合规范模式");
    }
  1. IllegalAirportException
    起飞和降落机场相同时,是不符合规定的,抛出该异常
if (departureLocation.equals(arrivalLocation))
    throw new IllegalAirportException("Airport " + departureLocation + "同时为起始终止机场");
3.1.1.2输入文件中存在标签完全一样的元素

SameLabelException:两个航班航班号日期全都一样,抛出该异常

for (FlightEntry<Plane> f : flights) {
   if (f.getPlanningEntryName().equals(planningEntryName)) {
    if (f.getDepartureTime().getMonthValue() == dt.getMonthValue()
      && f.getDepartureTime().getDayOfMonth() == dt.getDayOfMonth())
     throw new SameLabelException(f.getPlanningEntryName() + "存在相同日期的航班");
3.1.1.3输入文件中各元素之间的依赖关系不正确
  1. DateInconsistentException
    首行日期与信息内部出发日期不相同,抛出该异常
LocalDateTime dt = localDate.atStartOfDay();
  DateTimeFormatter df2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
  LocalDateTime dt2 = LocalDateTime.parse(departureTime, df2);
  if (!(dt.getMonth() == dt2.getMonth()) || !(dt.getDayOfMonth() == dt2.getDayOfMonth())
    || !(dt.getYear() == dt2.getYear()))
   throw new DateInconsistentException("首行时间" + dt + "与内部时间" + dt2 + "不一致");
  1. SameNumberLabelInconsistentException
    相同航班号内部信息不一致
if (f.getDepartureTime().getHour() != dt.getHour() || f.getDepartureTime().getMinute() != dt.getMinute()
      || f.getArrivalTime().getHour() != at.getHour()
      || f.getArrivalTime().getMinute() != at.getMinute())
     throw new SameNumberLabelInconsistentException(f.getPlanningEntryName() + "相同航班出发到达时间不一致");
  1. PlaneElementInconsistentException
    相同飞机内部信息不一致
for (FlightEntry<Plane> fl : flights) {
    if (fl.getResourceName().equals(planeName)) {
     if (!fl.getResource().getPlaneType().equals(type) || fl.getResource().getPlaneAge() != age
       || fl.getResource().getPlaneSeats() != seats)
      throw new PlaneElementInconsistentException("PlaneNumber " + "相同飞机号" + planeName + "的内部信息不一致");
    }
   }
  1. TimeGapOveraDayException
    起飞和降落时间间隔大于一天
if (dt.plusDays(1).isBefore(at)) {
   throw new TimeGapOveraDayException("Date " + dt + "与" + at + "相差大于一天");
  }

3.1.2处理客户端操作时产生的异常

  1. CancelWrongSateException
    当前状态不能取消时,用户执行取消操作抛出该异常
if (f.getStateofPlanningEntry().equals("WAITING")
       || f.getStateofPlanningEntry().equals("ALLOCATED")) {
      f.cancel();
      isContain = true;
     } else {
      throw new CancelWrongStateException(
        "State " + f.getStateofPlanningEntry() + "can't be cancelled");
     }
  1. DeleteUsingLocationException
    用户删除的位置已经被分配或者正在使用时,抛出该异常
if (fe.getOriginLocation().equals(location.getLocation())
       || fe.getTerminalLocation().equals(location.getLocation())) {
      throw new DeleteUsingLocationException("Location " + location.getLocation() + "is using.");
     }
  1. DeleteUsingResourceException
    用户删除的资源已经被分配或者正在使用时,抛出该异常
if (fe.getResourceName().equals(plane.getPlaneNumber())) {
      throw new DeleteUsingResourceException("Plane " + plane.getPlaneNumber() + "is using.");
  1. AllocateConflictLocationException
    用户分配的位置造成了位置使用冲突

  2. AllocateConflictResourceException
    用户分配的资源造成了资源使用冲突

3.2Assertion and Defensive Programming

3.2.1 checkRep()检查rep invariants

3.2.1.1Resource

以Train为例:AF、RI如下
在这里插入图片描述
设计对应的checkRep()
在这里插入图片描述

3.2.1.2LocationEntry

以MultipleLocationEntry为例AF、RI
在这里插入图片描述
设计对应的checkRep()
在这里插入图片描述

3.2.1.3ResourceEntry

以MultipleSortedResourceEntry为例AF、RI
在这里插入图片描述
checkRep()
在这里插入图片描述

3.2.1.4PlanningEntry

以TrainEntry为例AF、RI设计如下
在这里插入图片描述
checkRep()
在这里插入图片描述

Assertion/异常机制来保障pre-/post-condition

如加入资源检查资源是否为空,是否命名
在这里插入图片描述
删除资源也一样
在这里插入图片描述
添加资源项检查是否为空
在这里插入图片描述
检查后置条件:运行计划项后检查状态是否改变
在这里插入图片描述

3.2.3你的代码的防御式策略概述

用户输入的计划项,要判断是否符合规范模式,如flight中的航班号,飞机号等等,应该进行判断,如果不是就抛出异常,进行处理。
方法内部要判断,如此操作是否符合规范,如分配一个资源的时候,要进行资源冲突检查,活动app中更改一个位置要进行位置冲突检查。在计划项运行,暂停,停止,分配的操作中,在state类中添加WrongStateChangeException如果当前计划项的状态不符合转换要求,抛出该异常,Collection类中捕获异常,进行处理。
对某个计划项操作时,如果改计划项不在计划集合中,也需要能够判断出来,并返回false表示,进行不了用户指定的操作,让用户重新输入。

3.3Logging

3.3.1 异常处理的日志功能

在捕获到的异常中,添加logger.SEVERE()或logger.WARNING()
在这里插入图片描述

3.3.2 应用层操作的日志功能

在app中初始化一个logger
在这里插入图片描述
在app的主类中设置logger并且输出第一条信息
在这里插入图片描述
在每一个用户的选择下,增加一条日志信息,显示用户的操作
在这里插入图片描述

3.3.3日志查询功能

在Board中添加查询日志的方法按行读入文件,正则表达式判断,匹配出日期,日志级别,异常信息
在这里插入图片描述
还要进行异常判断
在这里插入图片描述
加入信息到表格中
在这里插入图片描述
在这里插入图片描述

3.4Testing for Robustness and Correctness

3.4.1Testing strategy

在这里插入图片描述
在这里插入图片描述

3.4.2测试用例设计

针对3.1设计的每个异常进行test
设计测试文件,读取文件,然后捕获异常,这里我重写了inputByFile使其能直接抛出异常,而不是捕获异常,这样在test里可以直接判断
在这里插入图片描述
还设计一个正确的文件,调用collection的方法进行测试
在这里插入图片描述
针对各个类,resourceEntry,PlanningEntry,LocationEntry分别构造一些测试用例,调用其中的方法进行测试
在这里插入图片描述

3.4.3测试运行结果与EclEmma覆盖度报告

有许多代码是直接向屏幕输出信息,无法测试,还有客户端代码无法测试
在这里插入图片描述
在这里插入图片描述

3.5SpotBugs tool

没有检测到bug

3.6Debugging

3.6.1EventManager程序

理解待调试程序的代码思想:
该程序是求当天中,所有事件重合的最大数,map中保存0到24的整数点,表示所有事件,value表示当前时间最大事件数,遍历所有的key找到最大的value即可
发现并定位错误的过程:
这里我将TreeMap又套了一层map,表示365天的记录,每当输入了一个天数,开始时间和结束时间,先判断当天的map有没有加入到temp中,没有的话就加入,同样遍历当天的map判断从start到end是否加入了该键值,如果没加入初始化为value=0
然后将从start到end的value加一,表示这些时间的事件数增加了一个,end处的value-1表示这里结束了一个事件,然后就可以遍历当天day的value找到最大的一个输出
在这里插入图片描述
修复之后的测试结果
在这里插入图片描述
在这里插入图片描述

3.6.2LowestPrice程序

理解待调试程序的代码思想:
该程序是给出几种优惠方案,在购买物品不超过需求的情况下,选择花费最少的方案,并输出最小花费
发现并定位错误的过程:
发现他判断优惠方案中的数量是否大于需求不完善,所以重新修改了一下,并且把递归求花费变成了,直接将他的优惠方案钱数加上,剩余的需求乘单价,即调用了一下dot方法
在这里插入图片描述
在这里插入图片描述
修复之后的测试结果
在这里插入图片描述

3.6.3FlightClient/Flight/Plane程序

理解待调试程序的代码思想:
该程序是遍历航班,随机找飞机,看是否能够避免时间冲突的情况下安排飞机
发现并定位错误的过程:
发现这里应该用equals()进行比较
在这里插入图片描述
然后这里比较日期应该用before和after来比较
在这里插入图片描述
改正如下:
在这里插入图片描述
还有sort方法应该重写comparator应该比较两个航班的起始和终止时间
在这里插入图片描述
修复之后的测试结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值