第三单元总结博客

JML理论基础与工具链

JML简介

JML(Java Modeling Language)是一种对Java程序进行规格化设计的表示语言,定义了Java程序中的方法规格和类型规格,便于代码实现,展开测试和提高代码的可维护性。

JML语法介绍

JML主要以Javadoc的方式嵌入Java代码中,以@开头。

原子表达式

\result 表示一个非void类型的方法执行后的返回值;
\old(expr) 表示一个表达式在方法执行前的值;
\not_assigned(x,y,...) 表示括号中的变量是否在方法执行过程中被赋值;
\not_modified(x,y,...) 表示括号中的变量在方法执行期间其值未发生变化。

量化表达式

\forall 全称量词修饰,表示指定范围的每一个元素都满足相应的约束;
\exists 存在量词修饰,表示指定范围的某一个元素满足相应的约束;
\sum 返回给定范围内的表达式的和;
\max\min 返回给定范围内的最值。

操作符

b_expr1<==>b_expr2b_expr1<=!=>b_expr2 等价关系操作符,操作符两边都是布尔表达式;
b_expr1==>b_expr2b_expr1<==b_expr2 推理操作符;
\nothing\everything 变量引用操作符,表示当前作用域访问的所有变量,前者为空集,后者为全集。

方法规格

requires P 前置条件,即要求条件P为真;
ensures P 后置条件,即要求方法执行返回结果一定满足条件P;
assignablemodifiable 副作用限定,分别表示可赋值,可修改。

JML相关工具链

  • JMLUnitNG: 根据JML自动生成测试文件

JMLUnitNG的部署与使用

  • 部署工作
    官网下载的解压会出问题,选择在GitHub上下载:https://github.com/OpenJML/OpenJML/releases/
    解压后,将三个jar包和下载的JMLunit的jar包与Solvers-windows文件夹放在同一个文件夹openjml里;
    在src文件夹下添加该openjml文件夹;

  • 需要注意的点
    在运行之前,需要对代码进行稍许修改。

0 <= i < groups.length 这种需要修改为 0 <= i && i < groups.length
new ArrayList<>() 这种需要补全,如 new ArrayList()
下图出现的 52,51是版本问题,不需关心。

第三单元总结博客_第1张图片

  • 使用
    在src文件夹下 git bash,指令为:java -jar $jmlunitng.jar的路径 $被测试文件的路径 $其他文件的路径
    针对本作业的 MyGroup.java文件,指令为 java -jar openjml/jmlunitng.jar com/oocourse/spec3/main/MyGroup.java com/oocourse/spec3/*
    生成测试文件后,运行MyGroup_JML_Test.java

  • 结果

[TestNG] Running:
  Command line suite

Failed: racEnabled()
Passed: constructor MyGroup(-2147483648)
Passed: constructor MyGroup(0)
Passed: constructor MyGroup(2147483647)
Passed: <>.addPerson(null)
Passed: <>.addPerson(null)
Passed: <>.addPerson(null)
Passed: <>.delPerson(null)
Passed: <>.delPerson(null)
Passed: <>.delPerson(null)
Passed: <>.equals(null)
Passed: <>.equals(null)
Passed: <>.equals(null)
Passed: <>.equals(java.lang.Object@27082746)
Passed: <>.equals(java.lang.Object@7bfcd12c)
Passed: <>.equals(java.lang.Object@24273305)
Passed: <>.getAgeMean()
Passed: <>.getAgeMean()
Passed: <>.getAgeMean()
Passed: <>.getAgeVar()
Passed: <>.getAgeVar()
Passed: <>.getAgeVar()
Passed: <>.getConflictSum()
Passed: <>.getConflictSum()
Passed: <>.getConflictSum()
Passed: <>.getId()
Passed: <>.getId()
Passed: <>.getId()
Passed: <>.getPeopleSum()
Passed: <>.getPeopleSum()
Passed: <>.getPeopleSum()
Passed: <>.getRelationSum()
Passed: <>.getRelationSum()
Passed: <>.getRelationSum()
Passed: <>.getValueSum()
Passed: <>.getValueSum()
Passed: <>.getValueSum()
Passed: <>.hasPerson(null)
Passed: <>.hasPerson(null)
Passed: <>.hasPerson(null)

===============================================
Command line suite
Total tests run: 40, Failures: 1, Skips: 0
===============================================

通过运行结果可以发现,JMLUnitng对于引用类的测试是用null进行测试的;诸如-2147483648,0和2147483647之类,是测试边界情况,强度并不大,且缺乏随机性。

单元作业

第九次作业

  • UML类图
    第三单元总结博客_第2张图片
    第九次作业并不难,根据jml进行代码实现就可以了,踩坑在Person类的isLinked()函数,把括号看岔了……

第十次作业

  • UML类图
    第三单元总结博客_第3张图片
    第十次作业在第九次的基础上新增了Group类,难点在isCircle()函数,强测上完美的tle了……

第十一次作业

  • UML类图
    第三单元总结博客_第4张图片
    第十一次作业需要自己实现两个方法,一个是queryMinPath(),求两点之间的最短路径,一个是queryStrongLinked(),判断两点之间是否强连通。
    求最短路径,我采用了dijkstra算法;
    求是否强连通,我先找出两点之间所有的路径构成的图,然后删去任意一条边,判断此图是否强连通,如果存在一种强连通的情况,那么两点之间就是强连通的。
    嗯……这次强测也很好的tle了:)

心得体会

一开始的JML的确是很好理解的,大部分都是根据注释填补代码的情况,只需要严格按照规格实现就OK,不过,慢慢的,尤其是第十一次作业里的queryMinPath()方法求两点间最短路径与queryStrongLinked()方法求两点之间是否强连通,JML只是给定了条件限制,具体实现完全靠自己发挥,JML的作用更多在于方便测试。
嗯还有一个单元,加油!

你可能感兴趣的:(第三单元总结博客)