哈工大2020软件构造Lab4实验报告

为了鄙视代写+抄袭+伸手党删除了一些“容易抄袭”的部分

有问题/询问省略部分——欢迎QQ交流!!!!!

本项目于5.19日实验课完成

(该更新的)更新完成

如果有所参考 请点点关注 点点赞GitHub Follow一下谢谢

HIT

2020春计算机学院《软件构造》课程Lab4实验报告

  • Software Construction 2020 Spring
  • Lab-4 Debugging, Exception Handling, and Defensive Programming
  • 版权声明:1183710109 郭茁宁

文章目录

  • 为了`鄙视代写+抄袭+伸手党`,`删除了一些“容易抄袭”的部分`
  • 有问题/询问省略部分——欢迎QQ交流!!!!!
  • 本项目于5.19日实验课完成
  • `(该更新的)更新完成`
  • 如果有所参考 请点点关注 点点赞[GitHub Follow一下谢谢](https://github.com/gzn00417)
  • 2020春计算机学院《软件构造》课程Lab4实验报告
  • 1 实验目标概述
  • 2 实验环境配置
  • 3 实验过程
    • 3.1 Error and Exception Handling
      • 3.1.1 处理输入文本中的三类错误(代码节选)
        • 3.1.1.1 DataPatternException
        • 3.1.1.2 EntryNumberFormatException
        • 3.1.1.3 SameAirportException
        • 3.1.1.4 TimeOrderException
        • 3.1.1.5 PlaneNumberFormatException
        • 3.1.1.6 PlaneTypeException
        • 3.1.1.7 PlaneSeatRangeException
        • 3.1.1.8 PlaneAgeFormatException
        • 3.1.1.9 SameEntryException
        • 3.1.1.10 HugeTimeGapException
        • 3.1.1.11 EntryInconsistentInfoException
        • 3.1.1.12 PlaneInconsistentInfoException
        • 3.1.1.13 SameEntrySameDayException
      • 3.1.2 处理客户端操作时产生的异常
        • 3.1.2.1 DeleteAllocatedResourceException
        • 3.1.2.2 DeleteOccupiedLocationException
        • 3.1.2.3 UnableCancelException
        • 3.1.2.4 ResourceSharedException
        • 3.1.2.5 LocationSharedException
  • 3.2 Assertion and Defensive Programming
      • 3.2.1 checkRep()检查rep invariants
        • 3.2.1.1 TimeSlot
        • 3.2.1.2 Location
        • 3.2.1.3 EntryState
        • 3.2.1.4 Resource
        • 3.2.1.5 PlanningEntry
      • 3.2.2 Assertion/异常机制来保障pre-/post-condition
        • 3.2.2.1 EntryState
        • 3.2.2.2 PlanningEntry
        • 3.2.2.3 PlanningEntryCollection
      • 3.2.3 你的代码的防御式策略概述
        • 3.2.3.1 Client-->API前置条件防御
        • 3.2.3.2 Client-->API后置条件防御
        • 3.2.3.3 API-->ADT前置条件防御
        • 3.2.3.4 API-->ADT后置条件防御
  • 3.3 Logging
      • 3.3.1 异常处理的日志功能
        • 3.3.1.1 需要终止当前操作的异常
        • 3.3.1.2 不需要终止当前操作的异常
        • 3.3.1.3 Assertion error
      • 3.3.2 应用层操作的日志功能
      • 3.3.3 日志查询功能
    • 3.4 Testing for Robustness and Correctness
      • 3.4.1 Testing strategy
      • 3.4.2 测试用例设计
      • 3.4.3 测试运行结果与EclEmma覆盖度报告
    • 3.6 Debugging(恕不给出详细错误)
      • 3.6.1 EventManager程序
      • 3.6.3 FlightClient/Flight/Plane程序

1 实验目标概述

2 实验环境配置

3 实验过程

3.1 Error and Exception Handling

在data/Exceptions/中构造了错误数据,并在ExceptionTest.java中测试了这些错误。

3.1.1 处理输入文本中的三类错误(代码节选)

第1-8个为不符合语法规则错误,第9个为元素相同错误,第10-13个为依赖关系不正确错误。
处理方法为:

try {……
throw new ……Exception();
} catch (……Exception e1) {
logger.log(Level.WARNING, e1.getMessage(), e1);
……
}

3.1.1.1 DataPatternException

原因:由于数据的常量错误而没有匹配到单个元素。
抛出异常方法:在正则表达式匹配时,若没有匹配到则抛出该错误。

if (!matcher.find()) {
throw new DataPatternException("Data: " + stringInfo + " mismatch Pattern.");
}

3.1.1.2 EntryNumberFormatException

原因:计划项编号不符合规则。
抛出异常方法:检查是否符合“前两个字符为大写字母,后2-4个字符为数字”。

/*** check entry number* @param planningEntryNumber* @throws EntryNumberFormatException*/
public static void checkEntryNumber(String planningEntryNumber) throws EntryNumberFormatException {if (Character.isUpperCase(planningEntryNumber.charAt(0))&& Character.isUpperCase(planningEntryNumber.charAt(1))) {for (int i = 2; i < planningEntryNumber.length(); i++) {if (!Character.isDigit(planningEntryNumber.charAt(i)))throw new EntryNumberFormatException(planningEntryNumber + " has incorrect format.");}} elsethrow new EntryNumberFormatException(planningEntryNumber + " has incorrect format.");
}

3.1.1.3 SameAirportException

原因:起飞和到达机场相同引起的错误。
抛出异常方法:对比两个机场字符串是否相等。

3.1.1.4 TimeOrderException

原因:起飞时间应该在到达时间之前(不能相等)。
抛出异常方法:首先try时间能否被parse,若不行则抛出DateTimeParseException;否则在finally中使用LocalDateTime.isBefore()方法比较时间先后。

/*** check time format and departure is before arrival* @param departureTime* @param arrivalTime* @throws TimeOrderException* @throws DateTimeParseException*/
public static void checkTime(String departureTime, String arrivalTime)throws TimeOrderException, DateTimeParseException {LocalDateTime dt = null, at = null;try {dt = LocalDateTime.parse(departureTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));at = LocalDateTime.parse(arrivalTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));} catch (Exception e) {throw new DateTimeParseException("The date time is not matched.", departureTime + arrivalTime, 0);} finally {if (dt != null && at != null) {if (!dt.isBefore(at))throw new TimeOrderException("Departure time " + departureTime + " is not before arrival time " + arrivalTime + " .");}}
}

3.1.1.5 PlaneNumberFormatException

原因:飞机编号不符合格式。
抛出异常方法:检查字符串长度以及首字母、后4位数字。

3.1.1.6 PlaneTypeException

原因:飞机类型不符合格式。
抛出异常方法:检查是否由字母和数字构成。

3.1.1.7 PlaneSeatRangeException

原因:飞机座位数范围错误。
抛出异常方法:转换为整数比较范围。

3.1.1.8 PlaneAgeFormatException

原因:飞机年龄非一位小数或整数,且介于0-30之间
抛出异常方法:查找小数点的位置,与字符串长度比较,得出几位小数,并查找区间。

3.1.1.9 SameEntryException

原因:存在两个航班,飞机和航班号都相等。
抛出异常方法:遍历所有计划项,两两比较是否存在上述条件。

3.1.1.10 HugeTimeGapException

原因:起飞时间和到达时间超过一天。
抛出异常方法:判断每个计划项的起飞时间晚1d是否比到达时间晚。

/*** check gap between leaving and arrival* @throws HugeTimeGapException*/
public void checkTimeGap() throws HugeTimeGapException {List<PlanningEntry<Resource>> entries = this.getAllPlanningEntries();int n = entries.size();for (int i = 0; i < n - 1; i++) {FlightSchedule<Resource> e = (FlightSchedule<Resource>) entries.get(i);LocalDateTime t1 = e.getTimeLeaving(), t2 = e.getTimeArrival();if (t1.plusDays(1).isBefore(t2))throw new HugeTimeGapException(t1.toString() + " is to early than " + t2.toString());}
}

3.1.1.11 EntryInconsistentInfoException

原因:相同航班号的航班信息(起降地点/时间)不一致。
抛出异常方法:检查每一对计划项,得到其时间和地点对象。

3.1.1.12 PlaneInconsistentInfoException

原因:不同的航班中出现相同的飞机。
抛出异常方法:遍历每一对飞机,若飞机号相同,但内容不相同,则出现不一致信息。

/*** check plane information consistent* @throws PlaneInconsistentInfoException*/
public void checkPlaneConsistentInfo() throws PlaneInconsistentInfoException {Set<Resource> planes = this.getAllResource();for (Resource r1 : planes) {for (Resource r2 : planes) {if (r1 != r2) {Plane p1 = (Plane) r1, p2 = (Plane) r2;if (p1.getNumber().equals(p2.getNumber()) && !p1.equals(p2))throw new PlaneInconsistentInfoException(p1.getNumber() + " has inconsistent information.");}}}
}

3.1.1.13 SameEntrySameDayException

原因:相同航班号的航班在同一天。
抛出异常方法:遍历比较

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

在App中遇到客户端操作异常时,抛出异常后使用Logger记录,并取消该操作。

3.1.2.1 DeleteAllocatedResourceException

原因:在删除某资源的时候,如果有尚未结束的计划项正在占用该资源。
抛出异常方法:遍历计划项,对于多个使用该资源的计划项,均检查计划项状态。捕获到异常后将“允许删除标签”设为false,最后显示弹窗声明删除失败。

Resource deletingResource = allResourceList.get(num);
boolean flag = true;
try {checkResourceAllocated(flightScheduleCollection, deletingResource);
} catch (DeleteAllocatedResourceException e1) {logger.log(Level.WARNING, e1.getMessage(), e1);flag = false;
}
flag &= flightScheduleCollection.deleteResource(deletingResource);
JOptionPane.showMessageDialog(resourceFrame, flag ? "Successful" : "Failed", "Deleting Resource", JOptionPane.PLAIN_MESSAGE);

3.1.2.2 DeleteOccupiedLocationException

原因:在删除某位置的时候,如果有尚未结束的计划项正在该位置执行。
抛出异常方法:遍历计划项,对于多个使用该位置的计划项,均检查计划项状态。
(与上DeleteAllocatedResourceException同理)
Check方法Spec如下:

/*** check location occupied* @param flightScheduleCollection0* @param location* @throws DeleteOccupiedLocationException*/
public static void checkLocationOccupied(FlightScheduleCollection flightScheduleCollection0, String location)throws DeleteOccupiedLocationException {List<PlanningEntry<Resource>> planningEntries = flightScheduleCollection0.getAllPlanningEntries();for (PlanningEntry<Resource> planningEntry : planningEntries) {FlightSchedule<Resource> flightSchedule = (FlightSchedule<Resource>) planningEntry;if (flightSchedule.getLocationOrigin().equals(location)|| flightSchedule.getLocationTerminal().equals(location))if (planningEntry.getState().getState().equals(EntryStateEnum.ALLOCATED)|| planningEntry.getState().getState().equals(EntryStateEnum.BLOCKED)|| planningEntry.getState().getState().equals(EntryStateEnum.RUNNING))throw new DeleteOccupiedLocationException(location + " is occupied");}
}

3.1.2.3 UnableCancelException

原因:在取消某计划项的时候,如果该计划项的当前状态不允许取消。
抛出异常方法:通过cancelPlanningEntry()–>setNewState()返回的Boolean来判断是否可取消。

3.1.2.4 ResourceSharedException

原因:在为某计划项分配某资源的时候,如果分配后会导致与已有的其他计划项产生“资源独占冲突”。
抛出异常方法:与DeleteAllocatedResourceException类似,与其不同的是在分配资源是遍历查找。

3.1.2.5 LocationSharedException

原因:在为某计划项变更位置的时候,如果变更后会导致与已有的其他计划项产生“位置独占冲突”。
抛出异常方法:与ResourceSharedException同理。该功能在Activity Calendar App中。

3.2 Assertion and Defensive Programming

3.2.1 checkRep()检查rep invariants

3.2.1.1 TimeSlot

TimeSlot的AF、RI如下:

/** AF:* arrival[i] represent the time it arrives locations[i]* leaving[i] represent the time it leaves locations[i]* * when Flight Schedule:* length == 2, arrival[0] == leaving[0], arrival[1] == leaving[1]* * when Activity Schedule:* length == 1, arrival[0] is ending time, leaving[0] is beginning time* * RI:* the length of arrival and leaving should be equal* leaving[i] should be later than arrival[i]* when i<length arrival[i] and leaving[i] should be non-null* * Safety:* do not provide mutator*/

由此可以设计checkRep()方法:

/*** check Rep*/
private void checkRep() {assert (arrival.size() == leaving.size());for (int i = 0; i < arrival.size(); i++) {assert (arrival.get(i) != null);assert (leaving.get(i) != null);}
}

3.2.1.2 Location

Location的AF、RI如下:

/** AF:* locations represent the locations in the plan* * RI:* locations should be as long as arrival and leaving in class TimeSlot* * Safety:* do not provide mutator*/

Location的Representation可以保证包括航班和高铁在内的“任意两个站不相同”。该checkRep()如下:

/*** check Rep*/
private void checkRep() {for (String strLocation1 : locations) {assert (strLocation1.length() > 0);for (String strLocation2 : locations) {if (strLocation1 != strLocation2)assert (!strLocation1.equals(strLocation2));}}
}

3.2.1.3 EntryState

EntryState的AF、RI如下:

/** AF:* the state enum's name represents the state * RI:* state must be in enums* Safety:* it's a mutable object, but do not let the outside modify state directly*/

checkRep()非常容易,略。

3.2.1.4 Resource

Resource的3个实现类均是immutable类型ADT,存储一定信息,因此其checkRep就是保证信息存储的变量符合格式,检查方法与抛出异常方法类似,因此对抛出异常的方法进行复用。以Plane为例:

/*** check Rep*/
private void checkRep() {try {FlightScheduleCollection.checkPlaneNumber(number);} catch (PlaneNumberFormatException e) {assert false;}try {FlightScheduleCollection.checkPlaneType(strType);} catch (PlaneTypeException e) {assert false;}try {FlightScheduleCollection.checkPlaneSeat(String.valueOf(intSeats));} catch (PlaneSeatRangeException e) {assert false;}try {FlightScheduleCollection.checkPlaneAge(Double.toString(age));} catch (PlaneAgeFormatException e) {assert false;}
}

3.2.1.5 PlanningEntry

在新建计划项时,资源、位置、时间、状态均被检查过,因此只要检查4者不为空,且标签正确即可。

private void checkRep() {assert (strPlanningEntryType.equals("FlightSchedule"));assert (location != null);assert (timeSlot != null);assert (state != null);assert (resource != null);
}

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

Assertion主要针对mutable对象的mutator。

3.2.2.1 EntryState

在修改状态时,前置条件和后置条件均为:当前状态合法。除了类型为高铁,否则不能为blocked。因此判断两次状态的合法性。

/*** set the new state* @param strPlanningEntryType in {"FlightSchedule", "TrainSchedule", "ActivityCalendar"}* @param strNewState* @return true if the setting is successful, false if not*/
public Boolean setNewState(String strPlanningEntryType, String strNewState) {assert (strPlanningEntryType.toLowerCase().contains("train")|| !this.getStrState().toLowerCase().equals("blocked"));if (this.setAvailability(strPlanningEntryType, strNewState.toUpperCase())){this.state = EntryStateEnum.valueOf(strNewState.toUpperCase());assert (strPlanningEntryType.toLowerCase().contains("train")|| !this.getStrState().toLowerCase().equals("blocked"));return true;}return false;
}

3.2.2.2 PlanningEntry

计划项的mutator在于分配资源和更改状态。
分配资源时,前置条件为:被分配的资源不能为空。以ActivityCalendar为例:

/*** allocate the resource to the flight schedule* set the state as ALLOCATED* @param resource* @param intResourceNumber* @return true if the resource is set and state is ALLOCATED*/
public Boolean allocateResource(R resource, int intResourceNumber) {assert (resource != null && intResourceNumber > 0);super.resource = resource;this.intResourceNumber = intResourceNumber;return this.state.setNewState(strPlanningEntryType, "Allocated");
}

更改状态时,后置条件为:更改后的状态不能为空且为某一合法状态。以CommonPlanningEntry.start()为例:

@Override
public Boolean start() {boolean flag = this.state.setNewState(strPlanningEntryType, "Running");assert (this.state != null && this.state.getState() != null);return flag;
}

其中,PlanningEntry中的TrainSchedule有操作“取第i个车厢”,对于该i的前置条件为:不能查询第1个站的到达时间且不能查询最后一个站的出发时间。以查询出发时间为例:

/*** get the LocalDateTime of leaving time of No.indexLocation Location* @param indexLocation* @return the LocalDateTime of leaving time of No.indexLocation Location*/
public LocalDateTime getLeavingTimeOfIndex(int indexLocation) {assert (indexLocation != TERMINAL);return super.getTimeSlot().getLeaving().get(indexLocation);
}

3.2.2.3 PlanningEntryCollection

在计划项集合类中,有许多关联到计划项编号的操作,前置条件要求计划项编号参数不能为blank。同理,所有有关查询操作的参数均不能为空白。

/*** search for a planning entry whose number matches the given* @param planningEntryNumber* @return the planning entry*/
public PlanningEntry<Resource> getPlanningEntryByStrNumber(String planningEntryNumber) {assert (!planningEntryNumber.isBlank());for (PlanningEntry<Resource> planningEntry : planningEntries)if (planningEntry.getPlanningEntryNumber().equals(planningEntryNumber))return planningEntry;return null;
}

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

代码的“错误传递”发生在客户端到API、API到ADT之间,因此在这两种传递过程的起始和完成阶段,都应该进行防御。

3.2.3.1 Client–>API前置条件防御

客户端和API之间,需要基于用户输入参数进行功能控制,因此用户输入的内容正确性决定了API功能实现的正确性。客户端的输入方法或API的方法起始阶段需要对用户输入进行检查。
例如FlightScheduleCollection.addPlanningEntry()中需要读入一段数据,在方法中进行了对各项参数的检查,错误则抛出包括EntryNumberFormatException在内的相应异常;而在查询指定计划项信息时,则是在FlightScheduleApp中先对该编号正确性进行检查(该操作委派给了FlightScheduleCollection)然后才获取指定信息。

3.2.3.2 Client–>API后置条件防御

在API操作完成之后,在客户端或API中需要对结果进行正确性的大致检查,避免一下明显错误情况;若API操作不当,可能在程序中引入隐式错误。
例如在启动计划项时,FlightScheduleApp在完成操作后弹窗显示操作结果;在暂停计划项之后,会检查该计划项类型是否为可暂停的计划项对象类型。

3.2.3.3 API–>ADT前置条件防御

在API的操作会对ADT进行影响,若ADT为可变的,则要求Setter()参数正确。检查参数正确可以在API的方法中,也可以在ADT的方法中。
例如API在获得某计划项的资源时,会判断该ADT的资源是否为空;在API需要获得高铁的第i站的到达时间,在ADT的方法中会对i的取值进行断言(不能为0)。

3.2.3.4 API–>ADT后置条件防御

在修改ADT的内容之后,需要确认修改后的ADT符合RI。此时,可以调用ADT私有方法checkRep()进行校验。在各个ADT中均有checkRep(),出现在构造器(immutable对象),也会出现在mutator(mutable对象)。

3.3 Logging

本实验中,日志功能的实现调用了 Java 的库 java.util.logging。并且日志功能仅支持在应用中实现,不支持在测试时使用。

private final static Logger logger = Logger.getLogger("Flight Schedule Log");

在后续的日志创建中,如果 Logger.getLogger(String name)的 name 参数和上述三个之一相同,那么日志变量将指向同一块内存区域,即共享同一 logger。然后对日志配置。
首先配置日志的输出语言为英文。

Locale.setDefault(new Locale("en", "EN"));

然后设置日志显示信息的最低级别(即包括了 INFO, WARNING 和 SEVERE)。

logger.setLevel(Level.INFO);

接着对三个 logger 配置加入相应的文件管理,使得日志可以写入到文件中。

FileHandler fileHandler = new FileHandler("log/FlightScheduleLog.txt", true);

对文件管理handler配置好文件写入的格式,采用SimpleFormatter格式文件,可读性高,但在检索时可能比较麻烦。

fileHandler.setFormatter(new SimpleFormatter());
logger.addHandler(fileHandler);

这样日志的配置就做好了。在应用类中,只需要加一个全局静态变量,调用已经创建的相关的 logger,再设置无需从控制台输出日志内容即可。除了应用类,凡是应用类调用的函数如果有异常被 catch 的话,其所在的类中,也应该有这个 logger 管理变量。
文件整体效果:

3.3.1 异常处理的日志功能

3.3.1.1 需要终止当前操作的异常

如果遇到需要终止当前操作的异常,在 catch 结束前,应该记录 SEVERE级别的日志信息,如:

try {
flightSchedule = flightScheduleCollection.addPlanningEntry(stringInfo.toString());
} catch (DataPatternException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
break;
}

3.3.1.2 不需要终止当前操作的异常

如果遇到不需要终止当前操作的异常,在 catch 结束前,应该记录WARNING 级别的日志信息,如:

try {
checkResourceShared(flightScheduleCollection,  flightScheduleCollection.getPlaneOfNumber(strResourceNumber));
} catch (ResourceSharedException e1) {
logger.log(Level.WARNING, e1.getMessage(), e1);
flag = false;
}

3.3.1.3 Assertion error

对于应用中遇到的 Assertion error,应该记录下 SEVERE 级别的信息。

3.3.2 应用层操作的日志功能

应用中使用功能在应用中使用的任何功能,都应该在调用之后马上生成 INFO 调用信息,在功能成功结束后,生成 INFO 成功信息。如:

switch (strOperation) {
case "Start":
logger.log(Level.INFO, "Start Planning Entry");
operationFlag = flightScheduleCollection.startPlanningEntry(planningEntryNumber);
break;

3.3.3 日志查询功能

首先处理字符串,并能够将所有的日志显示出来。通过委派复用Board功能,可视化JTable。以下,将增加方法参数(时间、事件类型和App类型),对日志项进行筛选,以下图形式进行显示。

通过正则表达式读入日志。

Pattern pattern1 = Pattern.compile("(.*?) apps\\.(.*?)App (.*?)\\.");
Pattern pattern2 = Pattern.compile("([A-Z]*?): (.*?)\\.+");

匹配后得出所需信息。

String time = matcher1.group(1);
String logType1 = matcher2.group(1);
String appType1 = matcher1.group(2);
String action = matcher1.group(3);
String message = matcher2.group(2);

转换时间后,检测时间是否匹配(设定:在WITHIN_MINUTE分钟以内):

if (!askedTime.isBlank()) {
askingTime = LocalDateTime.parse(askedTime, DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm"));
}
LocalDateTime timeFormatted = LocalDateTime.parse(timeString,
DateTimeFormatter.ofPattern("MMM dd, yyyy HH:mm:ss a"));
if (askingTime == null || 
(askingTime.plusMinutes(WITHIN_MINUTE).isAfter(timeFormatted) 
&& askingTime.minusMinutes(WITHIN_MINUTE).isBefore(timeFormatted))) {
……
}

同理,检测事件类型和App类型:

if (logType.isBlank() || logType.equals(logType1)) {
if (appType.isBlank() || appType.equals(appType1)) {……
}
}

方法Spec:

/*** show logs* @param askedTime* @param logType* @param appType* @throws IOException*/
public void showLog(String askedTime, String logType, String appType) throws IOException {}

最后通过GUI显示出选择日志,方法的按钮在visualization内的“Show Logs”。

3.4 Testing for Robustness and Correctness

3.4.1 Testing strategy

使用等价类和边界值的测试思想,为各 ADT 添加 testing strategy。以下以PlanningEntryAPITest为例:

/** Test strategy* * Location Conflict:* Add entries from without conflict to with conflict.* call method when they're added.* * Resource conflict:* Add entries from without conflict to with conflict.* call method when they're added.* * Find Pre Entry:* Add entries from non-pre-entry to has it, and to new pre-entry.* call method when they're added, and update the new entry closer to the asking.*/

3.4.2 测试用例设计

为每种Exception设计测试用例,保存在data/Exceptions/中。

主要有两种数据:最少需要一组数据的、最少需要两组数据的。当测试计划项数据文本内容各种Exception、以及资源相关Exception最少只需要一组数据。以PlaneSeatRangeException为例:

测试用例代码:

@Test
public void testPlaneSeatRangeException() throws Exception {exception.expect(PlaneSeatRangeException.class);exception.expectMessage(1000 + " is not in [50, 600].");String data = getOneData("data/Exceptions/PlaneSeatRangeException.txt");FlightScheduleCollection flightScheduleCollection = new FlightScheduleCollection();FlightSchedule<Resource> flightSchedule = flightScheduleCollection.addPlanningEntry(data);flightScheduleCollection.allocatePlanningEntry(flightSchedule.getPlanningEntryNumber(), data);
}

如此设计多种非法文件,促使程序出错,提高健壮性和正确性。

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

ExceptionTest测试运行结果:

所有测试运行结果:

EclEmma覆盖度测试:
语句覆盖度:

分支覆盖度:

复杂度覆盖度:

3.5 SpotBugs tool
没有Spot到Bugs。
之前有用到过,检测出实际返回类型和方法返回类型不一致的错误,还有可能为Null Pointer的错误。

3.6 Debugging(恕不给出详细错误)

3.6.1 EventManager程序

  • 理解待调试程序的代码思想:
    该程序要求若干时间区间交集数量的最大值。算法是标记+搜索。将区间的每一个整数点进行标记(用Map),查询是查找Map.values()最大值。

  • 发现错误并修改:

  • 修复之后的测试结果:

3.6.2 LowestPrice程序

  • 理解待调试程序的代码思想:
    该程序想要求在有special offer的情况下最优价格。算法思想是贪心。首先假设最低代价为所有均用零售,然后每次将一个special offer加入“购物车”,更新需求,再用新需求迭代求解。

  • 发现错误并修改:

  • 修复之后的测试结果:

3.6.3 FlightClient/Flight/Plane程序

  • 理解待调试程序的代码思想:
    该程序通过枚举每个航班,尝试安排飞机,确保没有与其他已经分配的航班冲突,最后确认是否能所有同时分配成功。

  • 发现并修正错误:

修复之后的测试结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/47063.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HIT csapp LAB1报告

实验报告 实 验&#xff08;一&#xff09; 目 录 第1章 实验基本信息 1.1 实验目的 1.2 实验环境与工具 1.2.1 硬件环境 1.2.2 软件环境 1.2.3 开发工具 1.3 实验预习 第2章 实验环境建立 2.1 Windows下 hello程序的编辑与运行&#xff08;5分&#xff09; …

[HITML]哈工大2020秋机器学习Lab4实验报告

Gtihub仓库 2020年春季学期 计算学部《机器学习》课程 Lab4 实验报告 姓名学号班号电子邮件手机号码 1 实验目的 实现一个PCA模型&#xff0c;能够对给定数据进行降维&#xff08;即找到其中的主成分&#xff09; 2 实验要求及实验环境 2.1 实验要求 测试&#xff1a; 首…

[HITML]哈工大2020秋机器学习Lab3实验报告

GitHub仓库 2020年春季学期 计算学部《机器学习》课程 Lab3 实验报告 姓名学号班号电子邮件手机号码 1 实验目的 实现一个k-means算法和混合高斯模型&#xff0c;并且用EM算法估计模型中的参数。 2 实验要求及实验环境 2.1 实验要求 测试&#xff1a;用高斯分布产生k个高…

SwiftUI——提供多种小组件(Widget)供用户选择

有时候app需要提供多种widget供用户选择/使用&#xff0c;那么可以使用以下方法&#xff0c;不过需要注意&#xff0c;每个app最多可以包含5种小组件&#xff08;Widget&#xff09;&#xff1a; 首先做几个小组件&#xff1a; //省略之前的Provider和SimpleEntey部分 //第一个…

iOS轻量级组件化管理工具,让你轻轻松松添加自己的小组件.

2019独角兽企业重金招聘Python工程师标准>>> TXRouter 轻量级组件化管理工具,让你轻轻松松添加自己的小组件.该工具原理简单、制作轻松、思路清晰等优点. TXRouter优点 比MGJRouter更加简单、使用更加方便原理简单、制作轻松、思路清晰 TXModel缺点 不能高大上定义U…

iOS14 Widget小组件开发实践1——了解Widget

iOS14带来了新的UI组件&#xff1a;WidgetKit&#xff0c;人称小组件&#xff08;用过安卓的都能理解&#xff09;&#xff0c;这货的前身其实就是iOS10时候引入的Today Extension。 Widget为应用程序提供了这样一种功能&#xff1a;其可以让用户在主屏幕上展示App中用户所关心…

如何用iOS14 Widget小组件自定义玩法

一.了解Widget iOS14带来了新的UI组件:WidgetKit,人称小组件(用过安卓的都能理解),这货的前身其实就是iOS10时候引入的Today Extension。 Widget为应用程序提供了这样一种功能:其可以让用户在主屏幕上展示App中用户所关心的信息。例如一款天气软件,其可以附带一个Widg…

iOS14 Widget开发踩坑(二)修正版-多个小组件

iOS14 Widget开发踩坑&#xff08;二&#xff09;修正版-多个小组件 前言添加多个小组件情况1.对于已经写好的一个小组件情况2.对于新建好还没写的小组件 Widgets的限制突破小组件个数限制的方法参考文献 前言 2020年12月3日 经过进一步的学习 发现了文章中还有很多错误&#…

IOS小组件(1):概述

IOS小组件(1):概述 引言小组件是什么?小组件概述小组件开发备注小组件实现原理结语引言 本系列文章作者是安卓开发,以安卓开发的视角学习IOS小组件,记录一下踩坑记录,如有讲得不对的地方,路过大佬多包涵。如果你是想深入学习小组件,建议您顺着笔者的编号顺序阅读本系列…

ios中在app应用内刷新小组件数据

需求&#xff1a; 我们需要在app应用内刷新时间线&#xff0c;让桌面小组件加载最新的内容。即app内修改了共享数据后&#xff0c;需要通知桌面小组件强制刷新&#xff0c;显示改变后的内容。 当某种情况影响到小组件的当前时间线时&#xff0c;您的 App 可以指示 WidgetKit …

android 仿苹果 小组件,仿ios14桌面小部件

仿ios14桌面小部件&#xff0c;这是一款面向广大安卓手机用户推出的高仿iOS14桌面插件软件&#xff0c;大家可以使用这款软件快速完成自己想要的桌面显示&#xff0c;多种插件一键点击轻松完成设置过程&#xff0c;让大家体验到同款iOS14桌面强大的功能&#xff0c;非常有意思的…

iOS14 小组件 开发1

前言:小组件的开发和我们正常情况开发App的逻辑是一样的,正常情况分为:网络请求,数据模型,view,渲染.只不过是小组件的开发使用了 swiftUI 语言来编写,所以要对SwiftUI的空间有所了解. 好!那我们接下来开始我们的小组件开发吧. 首先,创建Widget Extension 然后选择证书,起个名…

Android-为应用添加widget小组件

最近在实现为应用程序添加小组件的功能&#xff0c;记录一下开发过程。 1.添加一个小组件模板 设置组件类名称&#xff0c;其他属性按需求设置&#xff0c;这些属性在生成的文件中也可修改 ​​​​​​ 工程main目录下会生成类文件&#xff0c;res目录下生成资源文件&#x…

iOS 15 新增多个实用小组件

iOS 14 上线加入的桌面小组件功能非常受欢迎&#xff0c;因此苹果iOS 15新系统对小组件功能进行深度优化&#xff0c;并加入了多个实用又有趣的小组件。用户可以简单通过上下滑动来选择、重新排列、智能堆栈小组件&#xff0c;也可以对它们进行删除、智能旋转&#xff0c;还可以…

Widget小组件

目录 技能点 Widget背调 a. 设计定位 b. Widget小组件限制 c. Widget小组件 开发须知 d. 什么是 SwiftUI App Group 数据共享 a. 配置 App Groups 1、开发者账号配置&#xff0c;并更新pp证书 2、Xcode配置 b. 缓存数据共享-代码实现 1、文件存储 2. 沙盒存储&…

iOS_小组件widget基本功能

创建 在当前工程里新建target 选择Today Extension 独立应用 widget虽做为应用的扩展, 但却是两个完全独立的应用 widget上线需要单独申请 AppID 和 Bundle Identifier , 需要配置 证书 和 Provisioning Profiles(配置文件) 第三方pod导入, 也的重新导入一份 target MMWidg…

iOS 14-Widget小组件2—实现

Widget 实现 认识与配置实现效果图支持显示方式交互数据共享刷新策略网络加载屏幕适配支持多个小部件布局例子源码其他问题参考认识与配置 上一篇文章已经做了比较详细的介绍与创建配置iOS 14-Widget小组件1—初识 实现效果图 支持显示方式 @main 入口添加.supportedFamilie…

自定义开发苹果手机显示汽车小组件

实时获取汽车数据信息实时获取汽车定位信息&#xff08;点击地址进入高德&#xff09;显示当前位置的天气情况可定制显示当前城市是否限行可定制当前城市油价信息实时刷新最新数据 感兴趣的可以私聊加群

iOS 小组件 widget

苹果官网文档&#xff08;apple developer&#xff09;widgetkit 文章目录 1.创建小组件2.编辑小组件3.数据共享4.拖动排序5.参考链接 1.创建小组件 File -> New -> Target 搜索widget,点击next 勾上Include Configuration Intent, 表示需要编辑小组件&#xff0c;点击f…

iOS 小组件 widget 编辑小组件

返回小组件专栏&#xff1a;iOS 小组件 widget 文章目录 1.编辑小组件2.intentHandler 1.编辑小组件 如下图&#xff0c;编辑小组件&#xff0c;需要在GirlWidget.intentdefinition中配置 点击右下角的加号&#xff0c;新建一个枚举类型 枚举类型改名MyEnum,并添加三个值 …