面向对象第三单元反思与总结
随着学期过半,面向对象课程也迎来了第三单元,之后再经过一个单元,面向对象课程就结束了。本单元但是主题是JML的相关知识。
一、JML的梳理与总结
1.JML语言简介
JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种行为接口规格语言,有两种主要的用法:
(1)开展规格化设计。
(2)针对已有的代码实现。
JML以javadoc
注释的方式来表示规格,每行都以@起头。有两种注释方式,行注释和块注释。其中行注释的表示方式为//@annotation
,块注释的方式为/* @ annotation @*/
。
2.JML表达式和规格
下面给出两个表格简要介绍JML语言一些常见的结构:
表达式 | 作用 |
---|---|
esult |
表示一个非void类型的方法执行所获得的结果,即方法执行后的返回值 |
old(expr) |
用来表示一个表达式expr在相应方法执行前的取值。 |
ot_assigned(x,y,...) |
用来表示括号中的变量是否在方法执行过程中被赋值。 |
forall |
全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束。 |
exists |
存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束。 |
sum |
返回给定范围内的表达式的和 |
max 和min |
返回给定范围内的表达式的最大(小)值 |
此外还有诸如
ot_modified(x,y,...)
, ype(type)
, product
这样的表达式,本次作业没有涉及,但都很实用。
规格 | 作用 |
---|---|
requires | 前置条件,要求调用者须满足此条件 |
ensures | 后置条件,表示方法执行者确保方法执行返回结果满足此条件 |
assignable | 表示可赋值 |
modifiable | 表示可修改 |
pure | 有些方法不会对对象的状态进行任何改变,也不需要提供输入参数,无需描述前置条件,也不会有任何副作用,且执行一定会正常结束。 |
public normal_behavior | 一般指输入或方法关联this对象的状态在正常范围内时所指向的功能。 |
public exceptional_behavior | 与正常功能相对应的异常功能,后面一般跟上signals子句表示抛出的异常 |
3.工具链
(1) openJML
用来检查JML的规格和语法。
(2) JMLUnitNG
可以通过JML规格,对各类自动生成测试用例进行测试。
(3) JUnit
对某一个类生成测试模板,可以在这里编写测试用例来对方法进行测试。
上述工具的前两种我在本地均配置失败。。bug越改越多,未能成功运行。所以我主要讲一下第三种Junit:
首先在IDEA中导入相关jar包:
之后建立测试文件夹,生成测试文件:
类名右键 --> Go To --> Test --> Create New Test
之后点击想要测试的方法:
测试文件中,使用@Test修饰的方法为测试方法。使用@Before修饰的方法为初始化方法,在开始进行测试之前执行。 使用@After修饰的方法为在进行测试之后执行的方法, 通常用于释放资源。
在每一个测试方法中,首先需要构造测试用例,然后使用断言判断其是否能够得到预期的结果,常用断言有:
assertEquals | 是否相等 |
---|---|
assertTrue | 是否为真 |
assertFalse | 是否为假 |
assertNotNull | 是否不为null |
assertNull | 是否为null |
下面是一部分示例:
这是针对isCircle()
的单独测试,可以自由构造任何数据,缺点是较为繁琐,覆盖面不广,不如自动生成。
二、 架构设计与bug分析
这几次作业基本都是围绕已经给出的JML规格进行设计。
第九次作业:
几乎就是完全按照JML在写,唯一一个易错点在isCircle()
,自己和自己也认识,然后我采用的是BFS遍历的。
第十次作业:
增加了Group, 整体架构未发生太大变化,为了方便更新数据我将存放Person的容器改成HashMap。
第十一次作业:
增加了几个算法,这也是本次作业最难的地方,首先是最找最短路径的Dijkstra算法,然后是寻找点双连通分量的tarjan算法。但由于我之前从未使用过tarjan算法,最终我选择暴力查询,然后不出意外地超时了。。。
这几次作业出现的bug主要集中在算法上。在第九次作业时我只想着照搬JML的方法书写代码。第十次出现Group后我已经察觉到这似乎使用图来储存更合适,但最终未能实行。第十一次作业有了最短通路和点双连通分量,我才将整个数据结构大改,然后按照图的方法来写代码,但是由于图论部分较为生疏,写算法很费劲,也出了很多问题,导致强测结果不佳。
还有一个问题就是优化。我这几次作业写的第一版几乎都超时了,有些地方我优化完成,但有些到最后也没有调整好时间。究其原因,还是我的测试方法和工具用的不熟练,很多问题都只能手动debug,对于这几次作业来说非常麻烦,效果也不好。
三、 心得体会
JML作为一种规格语言,本质上是为了在写程序时提供一种设计方向,也便于交流和测试。但是写程序也不能完全照搬JML,最终的实现部分还是要自己完成,不管前期的算法,中期的优化,还是后期的测试,JML始终只是起到一个辅助作用,真正的代码还是该咋写咋写。这一单元我的成绩不够好,还是因为我本身算法部分偏薄弱,然后对于各种测试工具的使用不够熟练。就写代码这件事来说,只要基本功够扎实,不管在什么框架下完成都将会是很轻松的。