JML
JML的理论基础
JML即Java Model Language,是一种建模语言,用形式化的符号语言描述Java的类和方法。常用关键字及表达式如下:
关键字 | 意义 |
requires | 方法的前置条件 |
assignable | 方法修改域 |
signals | 抛出异常的条件 |
ensures | 方法的输出 |
normal_behavior | 方法的正常行为 |
exceptional_behavior | 方法的异常行为 |
also | 连接两个行为 |
表达式 | 意义 |
\result | 方法执行后的返回值 |
\old | 表示方法执行前表达式的取值 |
\not_assigned | 表示其后变量在方法执行过程中是否被赋值 |
\forall | 全称量词 |
\exists | 存在量词 |
\sum | 表示给定范围内表达式的和 |
\product | 表示给定范围内表达式的累乘结果 |
\max | 表示给定范围内表达式的最大值 |
\min | 表示给定范围内表达式的最小值 |
\num_of | 表示指定变量中满足相应条件的取值个数 |
(参考http://www.jmlspecs.org/)
应用工具链情况
目前支持JML的工具主要有OpenJml和JmlunitNg。
SMT Solver
部署及验证
实际上Idea及Eclipse都有OpenJml插件支持,但前者的插件现今已不支持,后者部署有点麻烦,我弄了好久还是报不知名的错。
下载:http://www.eecs.ucf.edu/~leavens/JML/download.shtml 解压后即可通过命令行使用。
也可通过向Idea中添加执行程序和参数的方法部署,如:https://www.cnblogs.com/hjw77/p/10777257.html
为缩短命令长度,我采取改包名的方法将所有代码置于同一文件夹testcode中。
使用openjml检验Person.java:
1 java -jar openjml.jar -exec .\Solvers\z3-4.7.1.exe -esc .\testcode\Person.java
结果运行正常(没有输出)
同理,使用openjml检验Group.java
1 java -jar openjml.jar -exec .\Solvers\z3-4.7.1.exe -esc .\testcode\Group.java
问题就来了,除了三目运算符的错误外,还提示找不到类的符号,检验引用其他类的Network.java也有相似错误。
与此同时,eclipse中的OpenJml却能支持的很好:
JMLUnitNg
部署及验证
下载:http://insttech.secretninjaformalmethods.org/software/jmlunitng/release_history.html
JMLUnitNg也可以通过命令行运行。
依次输入以下命令:
1 java -jar jmlunitng.jar testcode/Group.java
2
3 javac -cp jmlunitng.jar testcode/*.java
4
5 java -jar openjml.jar -rac testcode/Group.java
6
7 java -cp jmlunitng.jar testcode.Group_JML_Test
这次除了先前OpenJml的错误外,又新增OpenJml包内部错误,并且根据错误信息中的“++”无法定位错误之处,由此可见命令行下JmlUnitNg的使用体验并不令人满意。
在我自己写样例进行测试时,又发现JMLUnitNg的另一个弱点:
编译器对于泛型拥有自动推断能力,而显然JMLUnitNg没有,加上命令行环境下糟糕的手感,也不难解释为何其没有广泛应用。
历经两天多无数间断的尝试,基本可以断定,要么它和我的电脑八字相克,要么这东西就是个**。
作业架构设计
第一次作业基本上是跟着JML照猫画虎,没有做什么优化,尽管在测试中没有翻车,但给后来的作业埋下了隐患。
果不其然,在没有优化的条件下,第二次作业的强测ctle了一大片。最后经过增添若干缓存容器和状态标识,将cpu时间从七秒多压到两秒以下。
前两次作业在难度上没有体现,第三次作业涉及到部分图论的算法问题,比如最短路径,点双连通等。
关于判断点双连通的问题,之前一直没有找到高效又易于理解的算法,导致强测中这部分的失分较严重。
心得体会
这个单元接触的JML可谓是编程学习中的一片新天地,它消除了代码工程师和设计者之前的理解隔阂,帮助制订了唯一的代码合格标准,也为测试人员提供规范的测试角度和流程。另一方面,在使用JML测试工具的过程中,我看到这套理应称手的工具却连编译器的一两个小特性都没有具备,有时还会爆出难以理解的错误,实在让人感到可惜。
本单元我们正式接触了Junit测试方法,在一定程度上降低了自我测试的难度,提高了自测能力。