第三单元总结博客

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<People>()
下图出现的 52,51是版本问题,不需关心。

  • 使用
    在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: <<com.oocourse.spec3.main.MyGroup@44e81672>>.addPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@60215eee>>.addPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@65e579dc>>.addPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@61baa894>>.delPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@b065c63>>.delPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@768debd>>.delPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@490d6c15>>.equals(null)
Passed: <<com.oocourse.spec3.main.MyGroup@7d4793a8>>.equals(null)
Passed: <<com.oocourse.spec3.main.MyGroup@449b2d27>>.equals(null)
Passed: <<com.oocourse.spec3.main.MyGroup@5479e3f>>.equals(java.lang.Object@27082746)
Passed: <<com.oocourse.spec3.main.MyGroup@66133adc>>.equals(java.lang.Object@7bfcd12c)
Passed: <<com.oocourse.spec3.main.MyGroup@42f30e0a>>.equals(java.lang.Object@24273305)
Passed: <<com.oocourse.spec3.main.MyGroup@5b1d2887>>.getAgeMean()
Passed: <<com.oocourse.spec3.main.MyGroup@46f5f779>>.getAgeMean()
Passed: <<com.oocourse.spec3.main.MyGroup@18e8568>>.getAgeMean()
Passed: <<com.oocourse.spec3.main.MyGroup@33e5ccce>>.getAgeVar()
Passed: <<com.oocourse.spec3.main.MyGroup@5a42bbf4>>.getAgeVar()
Passed: <<com.oocourse.spec3.main.MyGroup@270421f5>>.getAgeVar()
Passed: <<com.oocourse.spec3.main.MyGroup@52d455b8>>.getConflictSum()
Passed: <<com.oocourse.spec3.main.MyGroup@4f4a7090>>.getConflictSum()
Passed: <<com.oocourse.spec3.main.MyGroup@18ef96>>.getConflictSum()
Passed: <<com.oocourse.spec3.main.MyGroup@6956de9>>.getId()
Passed: <<com.oocourse.spec3.main.MyGroup@769c9116>>.getId()
Passed: <<com.oocourse.spec3.main.MyGroup@6aceb1a5>>.getId()
Passed: <<com.oocourse.spec3.main.MyGroup@ba4d54>>.getPeopleSum()
Passed: <<com.oocourse.spec3.main.MyGroup@12bc6874>>.getPeopleSum()
Passed: <<com.oocourse.spec3.main.MyGroup@de0a01f>>.getPeopleSum()
Passed: <<com.oocourse.spec3.main.MyGroup@4c75cab9>>.getRelationSum()
Passed: <<com.oocourse.spec3.main.MyGroup@1ef7fe8e>>.getRelationSum()
Passed: <<com.oocourse.spec3.main.MyGroup@6f79caec>>.getRelationSum()
Passed: <<com.oocourse.spec3.main.MyGroup@67117f44>>.getValueSum()
Passed: <<com.oocourse.spec3.main.MyGroup@5d3411d>>.getValueSum()
Passed: <<com.oocourse.spec3.main.MyGroup@2471cca7>>.getValueSum()
Passed: <<com.oocourse.spec3.main.MyGroup@5fe5c6f>>.hasPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@6979e8cb>>.hasPerson(null)
Passed: <<com.oocourse.spec3.main.MyGroup@763d9750>>.hasPerson(null)

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

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

单元作业

第九次作业

  • UML类图

    第九次作业并不难,根据jml进行代码实现就可以了,踩坑在Person类的isLinked()函数,把括号看岔了……

第十次作业

  • UML类图

    第十次作业在第九次的基础上新增了Group类,难点在isCircle()函数,强测上完美的tle了……

第十一次作业

  • UML类图

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

心得体会

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

猜你喜欢

转载自www.cnblogs.com/mzny/p/12942523.html