• OO第三单元作业


    OO第三单元作业

    BearHuchao 2020年5月23日

    JML这个东西,放眼全国,北航独此一家。

    ——诸彤宇

    前言

    本单元的主题是形式化设计与验证。软件测试无法证明系统不存在缺陷,也不能证明它符合一定的属性。只有形式化验证过程可以证明一个系统不存在某个缺陷或符合某个或某些属性。本单元作业采用了JML这一形式化语言来进行描述。

    JML语言的理论基础及应用工具链

    The Java Modeling Language (JML) is a specification language for Java programs, using Hoare style pre- and postconditions and invariants, that follows the design by contract paradigm. Specifications are written as Java annotation comments to the source files, which hence can be compiled with any Java compiler.

    ——Java Modeling Language - Wikipedia

    理论基础

    JML使用类似Javadoc的形式将对方法的形式化描述以特定语法呈现给开发测试者。在使用中,以表达式为基本单位,组合使用表达式对方法规格和类型规格进行描述。其基本结构如下表所示:

    JML新增表达式一览
    类型 名称 备注
    原子表达式 esult 该非void方法返回结果
    old(expr) expr在该方法执行前的值
    ot_assigned(elems, …) elems是否在方法中被赋值
    ot_assigned(elems, …) 同上
    onnullelemets(container) container中不包含null
    ype(type) 返回type对应的Class
    ypeof(expr) 返返回expr对应的Class
    量化表达式 forall(vars; range; expr) 全称量词
    exists(vars; range; expr) 存在量词
    sum(vars; range; expr) 求和
    product(vars; range; expr) 求积
    max(vars; range; expr) 求最大值
    min(vars; range; expr) 求最小值
    um_of(vars; range; expr) 求可满足的元素个数
    集合表达式 JMLObjectSet {T x | modify} 抽象集合构造器
    操作符 <: 子类型关系
    <==> 等价关系
    ==> and <== 推理操作符
    othing 变量引用:空集
    everything 变量引用:全集

    此外,在进行方法规格描述的时候,还需要用到前置条件(requires)、后置条件(ensures)和副作用范围限定(assignable, modifiable)相关的关键词来进行进一步的描述。除此之外,还有normal_behavioralsoexceptional_behaviorsignalssignals_only等描述方法正常与异常的判断标准和返回值。

    Full documentation of JML syntax is available in the JML Reference Manual.

    工具链

    A variety of tools provide functionality based on JML annotations. The Iowa State JML tools provide an assertion checking compiler jmlc which converts JML annotations into runtime assertions, a documentation generator jmldoc which produces Javadoc documentation augmented with extra information from JML annotations, and a unit test generator jmlunit which generates JUnit test code from JML annotations.

    Independent groups are working on tools that make use of JML annotations. These include:

    • ESC/Java2 [1], an extended static checker which uses JML annotations to perform more rigorous static checking than is otherwise possible.
    • OpenJML declares itself the successor of ESC/Java2.
    • Daikon, a dynamic invariant generator.
    • KeY, which provides an open source theorem prover with a JML front-end and an Eclipse plug-in (JML Editing) with support for syntax highlighting of JML.
    • Krakatoa, a static verification tool based on the Why verification platform and using the Coq proof assistant.
    • JMLEclipse, a plugin for the Eclipse integrated development environment with support for JML syntax and interfaces to various tools that make use of JML annotations.
    • Sireum/Kiasan, a symbolic execution based static analyzer which supports JML as a contract language.
    • JMLUnit, a tool to generate files for running JUnit tests on JML annotated Java files.
    • TACO, an open source program analysis tool that statically checks the compliance of a Java program against its Java Modeling Language specification.
    • VerCors verifier

    由上述描述可知,JML有丰富的应用工具链。其主要的工具包括编译器jmlc,文档生成器 jmldoc,单元测试程序jmlunit

    JMLUnitNG

    工具的使用

    下载相关工具(jmlunitng.jaropenjml.jarjmlruntime.jarjmlspecs.jar),使用命令行工具生成测试文件。

    使用结果

    非常遗憾,在本人的作业中,由于使用了lambda表达式等Java 8语言特性,这使得使用老旧的工具进行验证不现实。

    JML_Error

    另外,由于该工具不能对接口类以及抽象方法类进行基于JML的形式化验证,遂放弃自行生成测试代码的想法。

    JML_Interface

    补救措施

    由于本人无法在本次作业的基础上对JMLUnitNG进行测试,故参照其他同学的测试结果,结合规格对生成的测试用例和数据进行简要分析。

    JML_Example_by_pgh

    可以看出,测试工具所使用的测试数据和用例都是基于一些极端值的,例如,对int类型,分别使用Integer.MAX_VALUE, Interger_MIN_VALUE以及0;对String类型,则使用""(空字符串)和null(空引用);对于其他更一般的对象,则仅使用null这一种值进行测试。(下图)

    JML_Example-1_by_pgh

    因此,仅仅使用本工具并不能进行完全的形式化验证工作,更准确的方法是使用SMT Solver等工具进行真正的形式化验证。

    设计策略

    基本模型

    使用HashMap管理数据,在此基础上,使用图论的相关方法对JML规格中的方法进行实现。更具体的请参照下列各图:

    第9次作业类图:

    U3HW9_UML

    第10次作业类图:

    U3HW10_UML

    第11次作业类图:

    U3HW11_UML

    主要困难及解决方案

    主要的困难是关于图的相关内容。由于Person类中使用ArrayList来保存了相关的人员关系情况,故可以将其视为图中的结点,并将该ArrayList视为邻接矩阵,进行图的相关计算。

    在进行最短路径的计算过程中,使用了优先队列进行了优化。

    另外,在Network的规格要求中出现了queryGroupPeopleSum, queryGroupRelationSum, queryGroupValueSum, queryGroupConflictSum, queryGroupAgeMean, queryGroupAgeVar等较多的查询方法。如果使用遍历计算相关结果,会造成极大的资源浪费,进而超时。故本人在Group类中维护了与这些查询方法相关的变量。当Group修改时,更新相关变量,在查询时直接返回即可,节省了大量计算资源。

    本次作业还使用了并查集算法。

    Bug分析

    目前最重大的一次Bug是在第10次作业中,由于看漏了JML中对group.length的约束(对最大值1111的特判),导致在强测中失分。

    另外,在第11次作业中遇到了CTLE的问题,正在排查有关情况。

    心得和体会

    • 在规格撰写方面,需要时刻将方法的变与不变放在心上,灵活运用离散数学学科中的相关内容对程序运行的前置条件和后置条件进行思考。在此基础上,需要对JML的语法熟练掌握。另外,需要注意方法在正常情况和异常情况的相关触发条件和返回值。
    • 在规格理解方面,首先需要静下心来,对方法规格进行概览,不要漏看、错看。在此基础上,对方法规格的理解需要结合类型规格。另外,在理解出现困难时,不妨看看方法的名称,结合文字描述再去看形式化语言描述往往会事半功倍。
  • 相关阅读:
    不同浏览器对于js中for循环的判断
    png格式图片背景不透明问题解决
    qq登陆错误提示
    T职场人生系列之二十四:程序员如何增加收入
    if [ $# eq 0 ]该语句是什么含义?
    动态IP修改注册表降低PING值教程(XP系统)
    c# List列表数据转换成树形结构
    net core EF 链接mysql 数据库
    net core 部署到windows 服务
    IdentityServer4 密码模式认证
  • 原文地址:https://www.cnblogs.com/bearhuchao/p/OOUnit3.html
Copyright © 2020-2023  润新知