面向对象OO第三单元总结
第三单元OO总结博客
1 梳理JML语言的理论基础、应用工具链情况
由于篇幅原因,这里只梳理几个在本单元常用的
注释结构
行注释:
//@annotation
块注释:
/* @ annotation @*/
例如:纯粹查询方法
/*@ pure @ */
,即方法的执行不会有任何副作用
JML表达式
原子表达式
\result:表示一个非 void 类型的方法执行所获得的结果,即方法执行后的返回值
\old(expr): 用来表示一个表达式 expr 在相应方法执行前的取值。作为一般规则,任何情况下,都应该使用\old把关心的表达式取值整体括起来。
量化表达式
\forall:全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束。
作业中的例子:
(\forall int i; <= i && (i < npath.length - ); containsEdge(npath[i], npath[i + ])));
保证isConnected 的前提之一是,这两个点之间有连续的边将他们相连(否则不通)
\exist:存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束
作业中的例子:
requires (\exists Path path; path.isValid() && containsPath(path); path.containsNode(fromNodeId)) &&
(\exists Path path; path.isValid() && containsPath(path); path.containsNode(toNodeId));保证isConnected 的前提之一,要存在某个Path,这个Path上包含这个点(否则就Not Found Exception)
操作符
子类型关系操作符: E1<:E2
等价关系操作符:
b_expr1<==>b_expr2
或者b_expr1<=!=>b_expr2
推理操作符:
b_expr1==>b_expr2
或者b_expr2<==b_expr1
。对于表达式b_expr1==>b_expr2
而言,当b_expr1==false
,或者b_expr1==true
且b_expr2==true
时,整个表达式的值为 true 。变量引用操作符
\nothing指示一个空集:
例如:
assignable \nothing
表示当前作用域下每个变量都不可以在方法执行过程中被赋值\everything指示一个全集
方法规格
正常行为规格normal_behavior
前置条件
通过requires子句来表示
例如增加一条路径的前提条件:增加的这条路径必须合法有效
requires path != null && path.isValid();
后置条件
通过ensures子句来表示
getPathId必须确保返回的ID确实属于当前存在的路径
ensures (\exists int i; 0 <= i && i < pList.length; pList[i].equals(path) && pidList[i] == \result);
副作用
使用关键词 assignable 或者 modifiable,这个函数要改什么变量,就在后面加那个变量的名字
例如addPath
/*@ normal_behavior
@ requires path != null && path.isValid();
@ assignable pList, pidList; 需要修改这两个List
省略一部分
@ also
省略一部分
@ assignable \nothing; 如果Path不合法,那么返回0,没有需要修改的东西
@ ensures \result == 0;
@*/
public int addPath(Path path);
异常行为规格expcetional_behavior
also: 有两种场景使用
除了正常功能规格外,还有一个异常功能规格,需要使用also来分隔。
父类中对相应方法定义了规格,子类重写了该方法,需要补充规格,这时应该在补充的规格之前使用also;
signals子句
结构为signals (***Exception e) b_expr,意思是当b_expr为true时,方法会抛出括号中给出 的相应异常e。
例子:
/*@ public normal_behavior
省略
@ also 下面是异常行为
@ public exceptional_behavior
@ assignable \nothing;
@ signals (PathNotFoundException e) path == null;
@ signals (PathNotFoundException e) path.isValid() == false;
@ signals (PathNotFoundException e) !containsPath(path);
@*/
public int removePath(Path path) throws PathNotFoundException;当 path == null条件成立,抛出异常
当 path.isValid条件成立,抛出异常
当容器内不含 path,抛出异常
在线OpenJML链接
2 部署SMT Solver,至少选择3个主要方法来尝试进行验证,报告结果
跳过
3 部署JMLUnitNG/JMLUnit,针对Graph接口的实现自动生成测试用例, 并结合规格对生成的测试用例和数据进行简要分析
生成数据
我研究了好久貌似OpenJML对MacOS不是很友好……好像也没有搞清楚TestNG怎么生成测试样例
写了一个python程序来生成测试指令
import random
SEQUENCE = 0;
ID = 1;
DOUBLE_ID = 2;
NONE = 3;
ID_NODE = 4;
queries = [("PATH_ADD", SEQUENCE),
("PATH_REMOVE", SEQUENCE),
("PATH_REMOVE_BY_ID", ID),
("PATH_GET_ID", SEQUENCE),
("PATH_GET_BY_ID", ID),
("PATH_COUNT", NONE),
("PATH_SIZE", ID),
("PATH_DISTINCT_NODE_COUNT", ID),
("CONTAINS_PATH", SEQUENCE),
("CONTAINS_PATH_ID", ID),
("DISTINCT_NODE_COUNT", NONE),
("COMPARE_PATHS", DOUBLE_ID),
("PATH_CONTAINS_NODE", ID_NODE)
] NUMBER = 100
PATH_LENGTH = 500
query_count = len(queries)
path_count = 0 def gen_node():
"""generate random node"""
return random.randint(-2**31, 2**31 -1) def gen_none():
""""""
return [] def gen_sequence():
"""generate id sequence"""
len = random.randint(2, PATH_LENGTH)
sequence = [] for i in range(len):
sequence.append(gen_node()) path_count + 1;
return sequence def gen_id():
"""generate id"""
return [random.randint(1, path_count * 2 + 1)] def gen_doubel_id():
"""generate two ids"""
return [random.randint(1, path_count + 1), random.randint(1, path_count + 1)] def gen_id_node():
return [random.randint(1, path_count + 1), gen_node()] # print(gen_sequence()) generators = {SEQUENCE : gen_sequence,
ID: gen_id,
DOUBLE_ID: gen_doubel_id,
NONE: gen_none,
ID_NODE: gen_id_node } for i in range(13):
(op, arg) = queries[0]
print(op + ' ' + ' '.join(map(lambda x: str(x), generators[arg]())))
for i in range(NUMBER):
(op, arg) = queries[random.randint(0, query_count - 1)]
print(op + ' ' + ' '.join(map(lambda x: str(x), generators[arg]())))
IDEA TestMe插件和 TestNG和OpenJML的安装历程
安装TestMe插件,可以直接在Plugin 的Market里面下载,TestNG失败
下载TestNG
Build TestNG from source code
TestNG is also hosted on GitHub, where you can download the source and build the distribution yourself:
然后把Jar包导入新创建的Maven项目当中,课程组的Jar包导入项目当中
在右侧边栏的Maven,点击加号,把课程组给的pom.xml导入
后来弄出了形如这样的一堆令人头疼的代码,遂放弃
@Test
public void testGetConnectedBlockCount() {
when(bfs.getBlockSize()).thenReturn(0);
when(bfs.updateGraph(any())).thenReturn(new HashMap<Integer, HashMap<Integer, Integer>>() {{
put(Integer.valueOf(0), new HashMap<Integer, Integer>() {{
put(Integer.valueOf(0), Integer.valueOf(0));
}});
}}); int result = myRailwaySystem.getConnectedBlockCount();
Assert.assertEquals(result, 0);
}
(错误示范)
正确使用OpenJML
在许多大佬的帖子中已经把如何生成测试代码讲得很清楚了
示例主程序在Demo.java里面
java -jar jmlunitng.jar src/Demo.java
javac -cp jmlunitng.jar src/*.java
然后会出现很多名字奇怪的.java文件,其中有一个叫Demo_JML_Test.java,也就是测试时要运行的主程序
我把生成的.java测试文件都加入到IDEA工程的src文件夹下面,需要导入的包有openjml.jar,jmlunitng.jar
但是我在运行Demo_JML_Test的时候有一些奇怪的报错 “org.jmlspecs.utils.JmlAssertionError 中是 protected访问控制”
于是把报错代码Catch 的 Exception删了
在艰苦卓绝的研究下,和修改了一堆版本不兼容的问题后,测试代码终于运行成功了!
(racEnabled尚未解决)
Junit 测试代码
创建单元测试可以直接在IDEA里面自动生成一个测试代码的框架
Junit中集中基本注解,是必须掌握的:
@BeforeClass – 表示在类中的任意public static void方法执行之前执行
@AfterClass – 表示在类中的任意public static void方法执行之后执行
@Before – 表示在任意使用@Test注解标注的public void方法执行之前执行
@After – 表示在任意使用@Test注解标注的public void方法执行之后执行
@Test – 使用该注解标注的public void方法会表示为一个测试方法
junit中的assert方法全部放在Assert类中,总结一下junit类中assert方法的分类。
Junit中部分Assert方法总结:(来自这个博客)
assertTrue/False([String message,]boolean condition); 判断一个条件是true还是false。感觉这个最好用了,不用记下来那么多的方法名。
fail([String message,]); 失败,可以有消息,也可以没有消息。
assertEquals([String message,]Object expected,Object actual); 判断是否相等,可以指定输出错误信息。 第一个参数是期望值,第二个参数是实际的值。 这个方法对各个变量有多种实现。在JDK1.5中基本一样。 但是需要主意的是float和double最后面多一个delta的值。
assertNotEquals([String message,]Object expected,Object actual); 判断是否不相等。 第一个参数是期望值,第二个参数是实际的值。
assertArrayEquals([java.lang.String message,] java.lang.Object[] expecteds, java.lang.Object[] actuals) ;
assertNotNull/Null([String message,]Object obj); 判读一个对象是否非空(非空)。
assertSame/NotSame([String message,]Object expected,Object actual); 判断两个对象是否指向同一个对象。看内存地址。
failNotSame/failNotEquals(String message, Object expected, Object actual) 当不指向同一个内存地址或者不相等的时候,输出错误信息。 注意信息是必须的,而且这个输出是格式化过的。
下面仅写出部分函数的测试代码
public class MyGraphTest {
MyGraph graph = new MyGraph();
int[] nodelist1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13};
int[] nodelist2 = {-1, 6, -2, -3, -4, -5, -6, -7, -8};
int[] nodelist3 = {0,1205, 999, 888, 777, 666};
@Before
public void before() throws Exception { // 每个方法检测之前,都另这个图里面有这三条路径
System.out.println("Ready to test " );
//MyGraph graph = new MyGraph();
graph.addPath(new MyPath(nodelist1));
graph.addPath(new MyPath(nodelist2));
graph.addPath(new MyPath(nodelist3));
} @After
public void after() throws Exception { // 每个函数检测完毕都会输出“test successfully!”
System.out.println("test successfully!");
} @Test
public void testContainsPath() throws Exception {
//TODO: Test goes here...
System.out.println("Testing ContainsPath!");
Assert.assertTrue(graph.containsPath(new MyPath(nodelist1)));
Assert.assertTrue(graph.containsPath(new MyPath(nodelist2)));
Assert.assertTrue(graph.containsPath(new MyPath(nodelist3)));
int[] nodelist4 = {9,9,9,9};
Assert.assertFalse(graph.containsPath(new MyPath(nodelist4)));
} @Test
public void testContainsPathId() throws Exception {
System.out.println("Testing contains Path id!");
Assert.assertTrue(graph.containsPathId(1));
Assert.assertTrue(graph.containsPathId(2));
Assert.assertTrue(graph.containsPathId(3));
Assert.assertFalse(graph.containsPathId(100));
} @Test
public void testRemovePath() throws Exception {
//TODO: Test goes here...
graph.removePath(new MyPath(nodelist1));
Assert.assertFalse(graph.containsPathId(1));
} @Test
public void testRemovePathById() throws Exception {
//TODO: Test goes here...
graph.removePathById(2);
Assert.assertFalse(graph.containsPath(new MyPath(nodelist2)));
} @Test
public void testContainsNode() throws Exception {
//TODO: Test goes here...
Assert.assertTrue(graph.containsNode(999));
Assert.assertFalse(graph.containsNode(14)); @Test
public void testIsConnected() throws Exception {
//TODO: Test goes here...
System.out.println("Testing is Connected@");
Assert.assertTrue(graph.isConnected(2,-8)); // 判断这个连接是对的
Assert.assertTrue(graph.isConnected(13,-8));
Assert.assertFalse(graph.isConnected(0, 1));
// 把这个文件拖到src文件夹里面即可运行 } }
愉快的Tests passed!
面向对象OO第三单元总结的更多相关文章
- 北航面向对象OO第三单元——JML
简介 本单元借助JML(Java Modeling Language),训练了我们关于的"规格(specification)"的意识和思想 本单元代码难度较低,简单来讲就是给你规定 ...
- OO第三单元作业总结
OO第三单元作业总结--JML 第三单元的主题是JML规格的学习,其中的三次作业也是围绕JML规格的实现所展开的(虽然感觉作业中最难的还是如何正确适用数据结构以及如何正确地对于时间复杂度进行优化). ...
- 规格化设计——OO第三单元总结
规格化设计--OO第三单元总结 一.JML语言理论基础.应用工具链 1.1 JML语言 JML(java modeling language)是一种描述代码行为的语言,包括前置条件.副作用等等.J ...
- OO第三单元——基于JML的社交网络总结
OO第三单元--基于JML的社交网络总结 一.JML知识梳理 1)JML的语言基础以及基本语法 JML是用于java程序进行规格化设计的一种表示语言,是一种行为接口规格语言.其为严格的程序设计提供了一 ...
- 【OO学习】OO第三单元作业总结
[OO学习]OO第三单元作业总结 第三单元,我们学习了JML语言,用来进行形式化设计.本单元包括三次作业,通过给定的JML来实行了一个对路径的管理系统,最后完成了一个地铁系统,来管理不同的线路,求得关 ...
- OO第三单元(地铁,JML)单元总结
OO第三单元(地铁,JML)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉并了解JML来是我们具有规格化编程架构的思想.这个单元的主题一开始并不明了,从第一次作业的路径到第二次 ...
- OO第三单元作业——魔教规格
OO第三单元作业--魔教规格 JML的理论基础和相关工具 JML(Java Modeling Language,Java建模语言),在Java代码种增加了一些符号,这些符号用来标志一个方法是干什么 ...
- OO第三单元个人总结
OO第三单元个人总结 JML理论与基础与应用工具链 JML是什么? Java建模语言(JML)是一种行为接口规范语言,可用于指定Java模块的行为 .它结合了Eiffel的契约设计方法 和Larch ...
- 2020 OO 第三单元总结 JML语言
title: 2020 OO 第三单元总结 date: 2020-05-21 10:10:06 tags: OO categories: 学习 第三单元终于结束了,这是我目前为止最惨的一单元,第十次作 ...
随机推荐
- leetcode 226. Invert Binary Tree(递归)
Invert a binary tree. 4 / \ 2 7 / \ / \ 1 3 6 9 to 4 / \ 7 2 / \ / \ 9 6 3 1 Trivia:This problem was ...
- 【leetcode刷题笔记】Valid Palindrome
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...
- [Luogu3960][NOIP2017]列队
luogu sol 震惊!\(NOIP\)居然也出数据结构! 话说回来,其实只需要对每一行的前\(m-1\)个人维护一个数据结构,然后对最后一列的\(m\)个人也维护一个数据结构就好了.具体的话写平衡 ...
- 洛谷【P1142】轰炸
我对状态空间的理解:https://www.cnblogs.com/AKMer/p/9622590.html 题目传送门:https://www.luogu.org/problemnew/show/P ...
- flume+kafka+storm+mysql架构设计
前段时间学习了storm,最近刚开blog,就把这些资料放上来供大家参考. 这个框架用的组件基本都是最新稳定版本,flume-ng1.4+kafka0.8+storm0.9+mysql (项目是mav ...
- [MySQL]关于Com_状态
MySQL 5.5官方文档: http://dev.mysql.com/doc/refman/5.5/en/server-status-variables.html#statvar_Com_xxx C ...
- 接口Comparator和Comparable的区别和联系
1. Comparator 和 Comparable 相同的地方 他们都是java的一个接口, 并且是用来对自定义的class比较大小的. 什么是自定义class: 如 public class Pe ...
- 愚人的linux内核2440移植札记(超曲折版)
http://blog.csdn.net/dreambegin/article/details/6904822 原来文章叫--编译内核之初体验.后来想了想,这篇文章让我体验了好多遍.不该叫这么大气的名 ...
- Ajax调用后台方法报未定义
需要在web.config中<system.webServer>节点下添加如下内容 <handlers> <add name="ajax" verb= ...
- 利用Admin-LTE项目搭建自己前端的开发框架模板
1 完整版本 1.1 下载admin-lte项目源代码 github下载地址:点击前往 三少云盘地址:点击前往 1.2 查看admin-lte精简主页源代码 页面地址:点击前往 注意:由源代码可以知道 ...