一、梳理JML语言的理论基础、应用工具链情况
JML语言是用于对Java程序进行规格化设计的一种语言,是一种行为接口规格语言(Behavior Interface Specification Language,BISL)。JML语言被用来描述代码的具体行为,可以用于开展规格化设计,以及提高代码的可维护性。JML基于Larch方法构建,BISL提供了对方法和类型的规格定义手段。JML是通过语义来严格描述Java模块的行为,防止出现设计错误的工具。JML还提供了各种验证工具,例如运行时断言检查器和扩展静态检查器,可帮助程序员进行开发。
应用工具链
JML语言需要各种测试工具来检验我们编写的JML规格的正确性。JML测试可以使用开源的JML编译器来编译含有JML标记的代码,所生成的类文件会在运行时自动检查JML规格,若程序未实现规格中的要求,JML运行期断言检查编译器会抛出一个uncheckedException来说明程序违背了哪一条规格。JMLdoc工具与Javadoc工具类似,可在生成的HTML格式文档中包含JML规范。还有工具JMLUnitNG可以根据规格的实现自动生成TestNG测试样例。
二、部署SMT Solver,进行验证
三、部署JMLUnitNG/JMLUnit进行简要分析
编写的测试文件:
public class Test { public Test() { } //@ public normal_behavior //@ requires ((x ^ esult) & (y ^ esult)) >= 0; //@ ensures esult == (i + j); //@ public exceptional_behavior //@ requires ((x ^ esult) & (y ^ esult)) < 0; //@ signals (ArithmeticException e); public int sum(int i, int j) throws ArithmeticException { int r = x + y; if (((x ^ r) & (y ^ r)) < 0) { throw new ArithmeticException("integer overflow"); } return r; } public static void main(String[] args) { } }
生成的测试用例如下:
[TestNG] Running: Command line suite Failed: racEnabled() Passed: constructor Test() Passed: static main(null) Passed: static main({}) Passed: static sum(-2147483648, -2147483648) Passed: static sum(0, -2147483648) Passed: static sum(2147483647, -2147483648) Passed: static sum(-2147483648, 0) Passed: static sum(0, 0) Passed: static sum(2147483647, 0) Passed: static sum(-2147483648, 2147483647) Passed: static sum(0, 2147483647) Passed: static sum(2147483647, 2147483647) =============================================== Command line suite Total tests run: 13, Failures: 1, Skips: 0 ===============================================
生成的测试用例主要针对int的边界条件和溢出检查,0、-2147483648、2147483647三个数出现频繁。同时检查了main函数的输入为null和{}情况。
四、按照作业梳理自己的架构设计,并特别分析迭代中对架构的重构
三次作业中Path类的变化不大,架构设计和重构主要体现在PathContainer、Graph和RailwaySystem三个类的构建上。可以看出三次作业里,MyGraph继承MyPathContainer,MyRailSystem继承MyGraph。这样基于上次作业的完成,避免机械的复制粘贴,能够最大限度的保持程序的可维护性,呈现出清晰的数据结构。同时为了增加新的功能,应该对旧框架做出合理的更改,通过重构来保证逻辑上的合理性。比如在RailwaySystem中增加了新的图类来计算最短路径问题。
五、按照作业分析代码实现的bug和修复情况
第一次作业因为int的溢出问题,导致偏序比较接口出现bug,使用Integer类的偏序比较接口即可修复。
第二次作业在公测和互测中没有出现bug。
第三次作业有一个因为计算出距离后的缓存没有在清理的时候完全清理,导致部分已经remove的路径可能仍然参加计算,导致出现bug。修复时增加了缓存的清理。另外因为算法问题导致强侧多个点ctle,应该在计算中充分利用已经求得的中间结果,进行加速。
六、阐述对规格撰写和理解上的心得体会
规格是在开发过程中必不可少的部分,这是一种开发人员之间约定遵守的“契约”。这一单元的作业从规格入手,通过一系列方法的实现,让我们对JML有了基本的理解:规格化语言一大好处是可以使代码清晰易懂,这一点在分工合作开发时有着重要的作用。另外规格化语言保证了代码的正确性,为以后的扩展提供了方便。从个人的体验上看,JML确实在设计和开发中起到了很大的作用,但对于一些较为复杂的方法,其JML的编写和理解是一个非常困难的事,实在让人苦恼。