2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)

目录

  • 1 实验目标概述
  • 2 实验环境配置
  • 3 实验过程
    • 3.1 Poetic Walks
      • 3.1.1 Get the code and prepare Git repository
      • 3.1.2 Problem 1: Test Graph
      • 3.1.3 Problem 2: Implement Graph
        • 3.1.3.1 Implement ConcreteEdgesGraph
          • (1)实现 Edge类
          • (2)实现ConcreteEdgesGraph类
          • (3)实现ConcreteEdgesGraphTest类
        • 3.1.3.2 Implement ConcreteVerticesGraph
          • (1)实现 Vertex类
          • (2)实现 ConcreteVerticesGraph类
          • (3)实现ConcreteVerticesGraphTest类
      • 3.1.4 Problem 3: Implement generic Graph
        • 3.1.4.1 Make the implementations generic
        • 3.1.4.2 Implement Graph.empty()
      • 3.1.5 Problem 4: Poetic walks
        • 3.1.5.1 Test GraphPoet
        • 3.1.5.2 Implement GraphPoet
        • 3.1.5.3 Graph poetry slam
    • 3.2 Re-implement the Social Network in
      • 3.2.1 FriendshipGraph类
      • 3.2.2 Person类
      • 3.2.3 客户端main()
      • 3.2.4 测试用例

1 实验目标概述

本次实验
训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象编程(OOP)技术实现 ADT。具体来说:
针对给定的应用问题,从问题描述中识别所需的ADT

  1. 设计 ADT规约(pre-condition、post-condition)并评估规约的质量
  2. 根据 ADT的规约设计测试用例;
  3. ADT的泛型化;
  4. 根据规约设计 ADT的多种不同的实现 针对每种实现,设计其表示representation)、表示不变 性 rep invariant)、抽象过程 abstraction function
  5. 使用 OOP实现 ADT,并判定 表示不变性是否违反、各实现是否存在表示 泄露 repexposure
  6. 测试 ADT的实现并评估测试的覆盖度;
  7. 使用 ADT及其实现,为应用问题开发程序;
  8. 在测试代码中,能够写出 testing strategy并据此设计测试用例。

2 实验环境配置

2.1 EclEmma的安装
进入EclEmma官网 https://www.eclemma.org/ 寻找安装方法,
发现可以使用eclipse自带的市场安装,打开搜索。
具体方法:Eclipse -> help -> eclipse market
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第1张图片

3 实验过程

请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。

3.1 Poetic Walks

对给定的接口Graph,完成他的两个实例类ConcretVerticesGraph和ConcreateEgdesGraph:
(1)首先分别构造两个实例类的rep类Vertex和Edge;
(2)用String作为L的特例,分别在两个实例类中实现Graph接口中的各个方法,写对应的test文件以确保其正确性,并且按照要求撰写每个方法的规约,AF,RI,以及rep exposure;
(3)将所有String变量替换为泛型L,实现图的泛型化。
2. 对给定的文本文件,按照给定规则建立有向图,调用Graph作为存储语料库的数据结构,利用该结构,对输入的字符串进行扩充。

3.1.1 Get the code and prepare Git repository

阅读http://web.mit.edu/6.031/www/sp17/psets/ps2/ ,遵循该页面内的要求完成编程任务。
获取初始代码:
https://github.com/rainywang/Spring2020_HITCS_SC_Lab2/tree/master/P1
在作业描述中若遇到 “commit and push”的要求 请将你的代码push到你的 GitHub Lab2仓库中。具体步骤为:
Git init
Git remote add origin xxxx你的github的地址
Git pull origin master
Git add .
Git commit -m “xxx”
Git push origin master
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第2张图片
MIT作业页面提及的文件路径,请按照下表的目录结构进行调整例如test/poet 应为“ test/ P1/ poet , src /poet 应为“ src P1/ poet 。
其他步骤请遵循 MIT作业页面的要求。

3.1.2 Problem 1: Test Graph

以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
首先要将泛型graph类型中的静态方法任意返回其中一种具体实现类型
在这里插入图片描述
对于非static类型的方法的测试策略
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第3张图片
1.测试add方法
add方法:a.The vertex has already included in the graph
b.The vertex has not already included in the graph
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第4张图片
2.测试set方法
* set方法:sourcenode targetnode:
* a.sourcenode,targetnode has already included in the graph
* b.one or two of the points has not included in the graph
* weight:

  • a.>0 b.=0
    3.测试remove方法
    remove方法:a. The vertex has already included in the graph,but no edges directly linked with it
  • b. The vertex has already included in the graph,but has some edges directly linked with it
  • c. The vertex has not already included in the graph
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第5张图片
    4.测试vertices方法
  • vertices方法:a.empty graph
  • b.unempty graph
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第6张图片
    5.测试source方法
    sources方法:a.the targetnode which has sourcenode(s) linked with
    b.the targetnode which has no sourcenode linked with
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第7张图片
    6.测试target方法
    target方法:a.the sourcenode which has targetnode(s) linked with
    b.the sourcenode which has no targetnode linked with
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第8张图片
    由于这是一个抽象的测试方法类,因此无法直接运行需要对具体类进行测试时扩展,完成对两种具体实现的测试时会直接调用这里的测试方法。

3.1.3 Problem 2: Implement Graph

3.1.3.1 Implement ConcreteEdgesGraph

(1)实现 Edge类

2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第9张图片
在这里插入图片描述
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第10张图片
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第11张图片
//function
private void checkRep();
public int getweight();
public L getSourcenode();
public L getTargetnode();
public String toString();
各个方法的具体实现这里不一一列出,功能基本较为简单主要为一些getter以及toString方法

(2)实现ConcreteEdgesGraph类

//Rep
private final Set vertices = new HashSet();
private final List edges = new ArrayList();
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第12张图片
//function:
private void checkRep();//每个function返回前检查rep不变
需要检查list中的不重复性,以及每一个edge的两端都在点集中
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第13张图片
@Override
public boolean add(String vertex);
(1)点存在:返回false
(2)不存在:调用list.add向vertices中添加该点
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第14张图片
@Override
public int set(String source, String target, int weight);
遍历edges:
(1)如果已经存在从source到target的一条边,记下这条边的权值,创建一条新的边(参数为source,target,weight),移除原来存在的边,加入新的一条边,替换掉edges中的旧边,返回旧边权;
(2)如果不存在,新建一条边(参数为source,target,weight),将其加入edges,返回0。
(3)如果weight=0,而且不存在这条边不需要做任何变化,如果存在这条边将这条边删除,并返回此条边的权值。
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第15张图片
@Override
public boolean remove(L vertex);
调用set.contains判断图中是否存在该顶点:(1)如果不存在,返回false;
否则,遍历edges,删除起点或终点是该顶点的边,遍历结束后调用list.remove从vertices中删除该顶点。
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第16张图片
@Override
public Set vertices();
copy一份vertices到新Set中,返回这个Set.采用防御式拷贝的方式防止不变量的暴露。

在这里插入图片描述
@Override
public Map sources(L target);
建立一个空Map,遍历edges,找出以target为终点的边edge;
weight=0时表示该边不存在,跳过;将edge.source->edge.weight加入Map,遍历结束后返回这个Map.
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第17张图片
@Override
public Map targets(L source);
建立一个空Map,遍历edges,找出以source为起点的边edge;
weight=0时表示该边不存在,跳过;将edge.source->edge.weight加入Map,遍历结束后返回这个Map.
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第18张图片
@Override
public String toString();
将所有边的toString连接在一起并输出。

(3)实现ConcreteEdgesGraphTest类

由于这个类继承了GraphInstanceTest类,因此通用的方法不需再编写测试,只需要测试ConcreteEdgesGraph中特有的方法,其他的方法继承GraphInstanceTest已经实现的方法。

  1. ConcreteEdgesGraph_toString方法的测试
  2. testgetweight测试Edge类中的get方法
  3. testgetSourcenode测试Edge类中的get方法
  4. testgetTargetnode测试Edge类中的get方法
  5. testEdgetostring()测试Edge类中的tostring方法

3.1.3.2 Implement ConcreteVerticesGraph

(1)实现 Vertex类

2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第19张图片
在这里插入图片描述
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第20张图片
在这里插入图片描述
//functions:
private void checkRep()检查不变性
public L getname();
public Map< L, Integer> getsources();
public Map< L, Integer> gettarget();
public void removesource(L source);
public void removetarget(L target);
public void addsource(L source,int weight);
public void addtarget (L target,int weight);
public String toString();//重写tostring方法

(2)实现 ConcreteVerticesGraph类

2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第21张图片
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第22张图片
//function:
注:由于这个类与edgegraph类等价实现garph接口,因此函数的实现有很大的类似性,这里仅仅写出函数的声明以及一些实现方法。具体代码不再复现。
@Override
public boolean add(String vertex);
(1)点存在:返回false
(2)不存在:调用list.add向vertices中添加该点

@Override
public int set(String source, String target, int weight);
遍历edges:
(1)如果已经存在从source到target的一条边,记下这条边的权值,创建一条新的边(参数为source,target,weight),移除原来存在的边,加入新的一条边,替换掉edges中的旧边,返回旧边权;
(2)如果不存在,新建一条边(参数为source,target,weight),将其加入edges,返回0。
(3)如果weight=0,而且不存在这条边不需要做任何变化,如果存在这条边将这条边删除,并返回此条边的权值。

@Override
public boolean remove(L vertex);
调用set.contains判断图中是否存在该顶点:(1)如果不存在,返回false;
否则,遍历edges,删除起点或终点是该顶点的边,遍历结束后调用list.remove从vertices中删除该顶点。

@Override
public Set vertices();
copy一份vertices到新Set中,返回这个Set.采用防御式拷贝的方式防止不变量的暴露。

@Override
public Map sources(L target);
建立一个空Map,遍历edges,找出以target为终点的边edge;
weight=0时表示该边不存在,跳过;将edge.source->edge.weight加入Map,遍历结束后返回这个Map.

@Override
public Map targets(L source);
建立一个空Map,遍历edges,找出以source为起点的边edge;
weight=0时表示该边不存在,跳过;将edge.source->edge.weight加入Map,遍历结束后返回这个Map.

@Override
public String toString();
将所有边的toString连接在一起并输出。

(3)实现ConcreteVerticesGraphTest类

由于这个类继承了GraphInstanceTest类,因此通用的方法不需再编写测试,只需要测试ConcreteVerticesGraph中特有的方法,其他的方法继承GraphInstanceTest已经实现的方法。
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第23张图片
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第24张图片
下面有关一些简单的方法的测试不给出具体的实现,在代码中各个测试类均有自己的测试策略,详见代码
@Test public void testgetname();
@Test public void testgetsoure();
@Test public void testgettarget();
@Test public void testaddandremovesource();
@Test public void testaddandremovetarget();
@Test public void testtostring();
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第25张图片
利用EclEmma测试覆盖度
这里几乎覆盖所有可能情况,有些地方在如极为简单的get方法没有涉及到,其次还有一些由于调用时的封装无法涉及已经完成了较为全面的覆盖。
在这里插入图片描述

3.1.4 Problem 3: Implement generic Graph

3.1.4.1 Make the implementations generic

将两个实例类中的所有String类的参数替换为泛型的参数(声明、函数参数、返回值、rep)可以使用eclipse中的自动补全的功能按照提示修改所有的具体类为泛型。这里不再赘述,在上述问题实现的基础上做一些简单的变化就可以实现
public class ConcreteEdgesGraph implements Graph
public class ConcreteVerticesGraph implements Graph

3.1.4.2 Implement Graph.empty()

修改Graph.empty为:
在这里插入图片描述
由于这个接口的两种实现方式的等价性因此在这个接口中的静态方法中返回任意一种方法即可这里以ConcreteEdgesGraph作为Graph默认的实例类,也可以用ConcreteVerticesGraph,二者是等价的。

3.1.5 Problem 4: Poetic walks

3.1.5.1 Test GraphPoet

2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第26张图片
涉及的函数有:
testemptyinput()//空文件输入
testsinglelineinput()//只有一行的文件输入
testmutilinesinput()//多行文件输入
testselectiveinput()//存在添加中间节点的选择问题
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第27张图片

3.1.5.2 Implement GraphPoet

//rep:
private Graph corpusGraph = Graph.empty();
用于存储文本文件读入后按规则建立的有向图
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第28张图片
//constructor:
public GraphPoet(File corpus) throws IOException
在这里插入图片描述
根据参数(文件),判断能否正常读入(否则抛出异常),并且调用poemGraph(corpus)方法创建好语料库(有向图)
主要思想为:用scanner类逐行读入文件,将每行按照“ ”进行分解,得到一个字符串数组,并将相邻的两个字符串组成一条边加入graph中既可以完成这个有向图的初始化建立。
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第29张图片
//funcution:
public String poem(String input);
在这里插入图片描述
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第30张图片
public String toString()//重写tostring方法
只需要调用图中实现的tostring方法即可。
这里在实现时提供了两个私有的辅助方法:

  1. private String findbridge(String a,String b)//在图中寻找是否存在ab之间的点如果有返回这个字符串没有则空串
    实现方法如下:
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第31张图片
  2. private String changetosmall(String inputString)//将一个字符串中的所有大写字母换成小写并返回。
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第32张图片

3.1.5.3 Graph poetry slam

这个问题是应用自己更新语料库文件中的字符串和输入的字符串input。
我们选择在main class中实现
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第33张图片
运行结果
在这里插入图片描述
语料库为:
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第34张图片

3.2 Re-implement the Social Network in

Lab1
在实现P1中ConcreteEdgesGraph以及ConcreteVerticesGraph类 的基础上实现FriendshipGraph,即用import语句导入P1中实现的图结构通过基本操作实现FriendshipGraph中addVertex,addEdge和getDistance三个接口。在Lab1中的规约不变要求测试在修改之后的FriendshipGraph中仍可以正常通过。

3.2.1 FriendshipGraph类

public void addVertex(Person person)
遍历父类的vertices(),如果存在一个元素的name域与Person的name域相等,证明这个点已经存在,输出提示并结束程序,否则调用父类的add(person)将该点加入。
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第35张图片
public void addEdge(Person p1, Person p2)
先调用父类的set(p1,p2,1),如果返回值为0证明这两个点之间不存在边,否则证明这两个点之间已经有边存在,输出提示
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第36张图片
public int getDistance(Person p1, Person p2);
使用BFS算法求p1与p2之间的最短距离,BFS需要遍历邻居节点时调用父类接口的targets(p1)就可以获得p1的所有邻居节点。
主要步骤代码如下:
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第37张图片
public Set getListofPersons();//采用防御式拷贝的方法返回person的set
在这里插入图片描述
public static void main(String Args[])
与Lab1相同

3.2.2 Person类

//rep:
private final String name;//该person的名字
//constructor:
在这里插入图片描述
//function:
没有特殊的一些方法,主要为一个chekrep检查不变量的方法,以及一个get方法和一个重写tostring方法。
注:这里没有将检查重名的行为交给FriendshipGraph中的addvertices方法而不是在person中因此,此时person的设计较为简单,仅仅存放一个person的名字即可。

3.2.3 客户端main()

由于实验指导书中已经给出一个简单的main()客户端的例子,这里main仅仅是一个简单的示例就不做过多的更改与扩展,采用指导书中所给出的的main()方法作为客户端,并会在test中对整个程序进行更加完备的测试。
在这里回答所提出的两个问题,并已经在程序中做出相应的扩展
1.运行的结果理论应该是:-1 -1 0 -1 运行代码所得结果与期望一致
2.我们修改addVertex函数,在对加入的person进行检查,如果这个person的name与之前我们加入过的点相同,并且不是同一个点重复加入,则判定为违反了Each person has a unique name,会打印提示信息并exit(-1)
相关功能已经实现并在test有相应的测试用例
2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第38张图片

3.2.4 测试用例

在这个测试用例中主要实现对三个方法的测试。

  1. public void addVertextest()
    这里测试包括了:
    a.正常地加入一个点 b.重复加入同一个点 c.加入一个重名的点(未测试): 会导致程序退出 d.继续加入其他点并检查之前的点是否有影响
    测试方式:assertTrue(graph.listofpersons.contain(……))
    具体代码如下:
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第39张图片
  2. public void addEdge()
    这里测试包括了:
    a. 测试与未加入的点连线 b. 添加自身到自身 c.正常加入两个关系
    d. 加入已存在的关系 e. 加入ab之后再加入ba
    测试方法:assertFalse(graph.addEdge(aPerson, dPerson))//用addEdge的返回值测试
    代码如下:
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第40张图片
    3.public void getDistancetest()
    这里测试所构建的图为:
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第41张图片
    测试方法为:assertEquals(expected distance, graph.getDistance(aPerson, aPerson))//用断言assertEquals将期望的距离与实际距离比较。
    主要代码如下:
    2020年春季学期 计算机学院《软件构造》课程——Lab2总结(P1、P2)_第42张图片

你可能感兴趣的:(软件构造实验总结及报告,java)