2022年春季学期计算学部《软件构造》
课程Lab2实验心得
目录
3.1.1 Get the code and prepare Git repository
3.1.3 Problem 2: Implement Graph
3.1.4 Problem3: Implement generic Graph
3.2 Re-implement the Social Network in Lab1
1. 实验目标概述
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象编程(OOP)技术实现 ADT。具体来说:
- 针对给定的应用问题,从问题描述中识别所需的 ADT;
- 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
- 根据 ADT 的规约设计测试用例;
- ADT 的泛型化;
- 根据规约设计ADT的多种不同的实现;针对每种实现,设计其表示 (representation)、表示不变性(rep invariant)、抽象过程(abstraction function)
- 使用OOP实现 ADT,并判定表示不变性是否违反、各实现是否存在表示泄露(rep exposure);
- 测试 ADT 的实现并评估测试的覆盖度;
- 使用 ADT 及其实现,为应用问题开发程序;
- 在测试代码中,能够写出 testing strategy 并据此设计测试用例。
-
2. 实验环境配置
Eclipse IDE for java Developers-2022-03
Javahttps://developer.oracle.com/java/GitHub Desktop
EclEmma Java Code Coverage 3.1.3
3. 实验过程
该任务是实现一个图的模块,基于此实现GraphPoet类
实现Graph类的方法:add、set、remove、vertices、sources、targets;
3.1 Poetic Walks
利用实现的Graph类,应用图的思想,实现GraphPoet类,如果输入的文本的两个单词之间存在桥接词,则插入该桥接词;若存在多个单一桥接词,则选取边权重较大者。
3.1.1 Get the code and prepare Git repository
使用GithubDesktop,add,clone,导入eclipse
3.1.2 Problem 1: Test Graph<String>
编写测试样例,并使用emptyInstance()方法编写GraphInstanceTest.java,测试代码覆盖度:
静态测试本身不复杂,只要对于Graph提供的规约测试即可,对于graphInstance,只要将graph想象成一个黑盒,按照ADT规约去测试它就可以
3.1.3 Problem 2: Implement Graph<String>
重写Graph里的方法,分别写出以点为基础的图和以边为基础的图
- Implement ConcreteEdgesGraph
以边为基础实现,共包含以下两个部分:
EDGE{
- Source:边的起始点
- Target:边的终止点
- Weight:边的权重
- Edge:边本身,初始化上述三个成员变量
- Checkrep:检查边权是否是正整数,始末点是否不同
- SameEdge:判断是否出现相同的边
- ToString:输出边的相关信息,方便测试和调试
}
ConcreteEdgesGraph{
- Add:增加点
- Set:增加边
- Remove:删除点,并删除依赖的边
- Vertices:返回vertices
- Sources:返回起点集合
- targets:返回终点集合
- toString:输出图的信息
- Set<L>vertices:点集
- List<Edge<L>>edges:边集
- CheckRep:检查有无空的点和边
}
测试结果
覆盖度测试结果:
以点为基础实现,包含以下几两个部分
Vertex{
- Sources:返回inedges
- Targets:返回outedges
- Setedge:添加一个新的边,存在则重新添加,不存在则加入新的边
- RemoveEdge:删除边,不存在返回0
- Thisvertex:存储这个点本身的名字
- Inedges:指向该点的边集
- Outedges:由该点指出的边集
- Vertex:初始化标识
- CheckRep出度入度都大于0,边权大于0
}
Concreteverticesgraph{
- Add:增加一个点(若不同)
- Set:增加一个边
- Remove:删除相关的边
- Sources:调用vertex类的即可
- Targets:同上
- List<vertex<L>>vertices:点集
- Checkrep:点不能没有标识,边权大于0
}
测试结果:
覆盖度
3.1.4 Problem3: Implement generic Graph<L>
将每一个实例部分均修改,可以通过报错找到大部分位置,为Graph.empty()增加一个返回实例。
3.1.5 Problem4: Poetic walks
给出一个语料库,根据这些文本生成一个单词图,并给定一个语句输入,自动补全语句中可能需要完善的部分每个不同的单词看做一个顶点,相邻的单词直接有一个有向边,检查长度为2的路的个数。划分多个等价类:两个单词不连接,有一个连接词,有多个连接词用文件输入单词,像lab1那样,用split分割为数组,依次增加点和边,若已有边则权重加一。处理时,检查相邻词汇之间长为2的路径,方法是一个点的sources和另一个的targets去比较即可
3.1.6 使用Eclemma检查测试代码覆盖度
程序结构如下:
3.2 Re-implement the Social Network in Lab1
这部分任务是用新的Graph类重写lab1中的Friendshipgraph,节点使用person类型,所以L即为Person。
3.2.1 FriendshipGraph类
- Graph<Person>graph:调用Graph.empty生成一个新图
- Addvertex:增加一个点
- Addedge:增加一个边
- Getdistance:利用深度优先搜索从起点搜索终点
-
3.2.2 Person类
给每个人建立一个Person对象,设置一个私有的姓名
3.2.3 客户端main()
和lab1中一样的方式进行测试,测试四个添加和不同人之间的距离是否正确即可
3.2.4 测试用例
这里依然采用和lab1中一样的示例,但由于这里我保留了扩展成有向图的函数但按照无向图去构造,所以增加一个新的点来测getinstance能否正常返回-1
用例如下:
3.2.5 提交至Git仓库
Git add*.doc
Git commit -m “finish P2”
Git push
代码结构如下:
4. 实验过程的经验、教训、感想
4.1 实验过程中的经验教训
在实验中,我一开始没有充分结合实验课和知识课,导致对于实验内容了解不足,于是做了很多前期准备仍然没有抓手,对于ADT的规约等部分不是很熟练,应该先掌握理论之后再尝试进行实战,在实验中我感悟到了ADT的强大之处,假使ADT不是我编写,我也可以为其编写充分的测试样例,这使得协同作业很方便。
4.2 针对以下方面的感受
- 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
面向ADT编程更加抽象也更加实用,只要双方约定好接口的格式就可以很容易相互协作分工,且ADT能力更强,体系更大,使用更舒服。
- 使用泛型和不使用泛型的编程,对你来说有何差异?
使用泛型的编程更抽象,更强调代码前后的一致性,并且适用程度更高,使用范围更广,不使用泛型的编程更直接具体。
- 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
在给出ADT的规约之后,根据规约去书写测试用例可以让测试者更容易考虑的完全,测试用例覆盖度更高,也能增加团队协作的效率,只需要根据给出的接口进行测试,不依赖先写好ADT,但由于ADT也是由我自己编写,还是会先想好怎么写再写测试用例,并不完全做得到黑和测试
- P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
复用可以减少开发成本,效率更高
- P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?
已经开始有了一些适应,先写Spec是很重要的,自主设计ADT是很有趣的,oop语言虽然不是每个小细节都像C语言那样由自己所打磨,但自己设计一个如臂指使的ADT还是很有成就感的,设计的过程其实更难,比实现更重要。
- 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
这些工作可以提高程序的健壮性,也可以让别人拿到你的代码之后能更快的理解或和你协同工作。
我愿意这么做,对于一个体量较大的工程,前端,后端,软件测试员需要这样的方式去协调工作,这很高效。
- 关于本实验的工作量、难度、deadline。
工作量和难度都适中,主要是以体会设计ADT的过程和测试过程为主,ddl较晚,这可能使得实验三时间不足(与密集的考试复习完全重合,强烈建议协调)
- 《软件构造》课程进展到目前,你对该课程有何体会和建议?
基础理论内容比较多,完全可以增加学时,这门课实用性很强,应该占有更大的学分,实验课将理论和编程结合,每周都有,但两三周作为一个整体,和知识契合度有所下降,希望可以拆散开来。