软件构造Lab2

实验二

个人博客url 软件构造lab2

实验目标概述

本次实验训练抽象数据类型(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并据此设计测试用例。

实验环境配置

环境配置:
IntelliJ IDEA 2020.3.1 (JDK 1.8 Junit 4.12(下载到lib目录中))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AdcXz6B3-1624860192645)(/SoftwareConstruction/experiment2/image002.png)]

GitHub Lab2 URL:
github url

实验过程

Poetic Walks

Get the code and prepare Git repository

使用git clone命令从远程仓库中获取源代码

git clone https://github.com/rainywang/Spring2020_HITCS_SC_Lab2/tree/master/P1

并在本地使用git init命令建立git仓库。

通过git add . 命令添加所有文件,在通过git commit -m “message”的命令,提交本地项目,通过git remote add origin <url>的命令关联远程仓库,并使用git push -u origin master的命令,将其推送到远程github仓库。

我们也可以通过git log命令,详细查看提交记录,可以查看到不同版本。

总结:我们可以通过git status查看状态,git add . 添加文件,git commit -m “描述信息”生成版本控制,git log查看不同版本。

Problem 1: Test Graph <String>
  • 1> public boolean add(L vertex);

设计:我们此时根据图是否为空,待添加顶点是否在图中作为输入的区分,因此我们应该对这几种情况的笛卡尔积做测试。将此时分为三种情况:

图为空,则vertex不在图中

图不为空,且vertex不在图中

图不为空,且vertex在图中

思路、过程:根据方法上方的注释分析,此时我们需要添加一个顶点到这个图,若该图中没有包含该顶点,则返回true,否则我们应该返回false。因此,对于这种情况,我们应该测试输入作如下分区:图是否为空图,当前顶点是否在图中。并对这两种情况做笛卡尔积,排除掉图为空,且当前顶点在图中的情况。

结果:分别对三种情况做测试,测试通过。

  • 2> public int set(L source, L target, int weight);

设计:此时根据图是否为空,当前的边是否在图中,当前的顶点是否在图中,以及weight是否为0分区。对这些分区求笛卡尔积做测试,由于分区的笛卡尔积存在某些不可能出现的情况,故此时分为以下几种情况:

顶点在图中,边不在图中,图不为空,weight=0

顶点不在图中,边不在图中,图为空,weight=0

顶点在图中,边在图中,图不为空,weight=0

顶点在图中,边在图中,图不为空,weight!=0

顶点在图中,边不在图中,图不为空,weight!=0

顶点不在图中,边不在图中,图为空,weight!=0

思路、过程:根据方法上方的注释分析,我们需要添加,改变,或删除一个加权有向边在这个图中,如果weight!=0,则添加一条边,或更新该边的权值。若给定标签的顶点没有出现,则带有给定的标签的顶点将被添加到图中,若weight==0,且存在这条边,则去除这条边,返回之前边的权值。因此我们可以据此,对图是否为空,当前的边是否在图中,当前的顶点是否在图中,以及weight是否为0分区

结果:分别对以上几种情况测试,测试通过。

  • 3> public boolean remove(L vertex);

设计:此时可以根据当前顶点是否在图中进行分区,则一共分为两种。

当前顶点在图中

当前顶点不在图中

思路、过程:根据方法上方的注释分析,从图中去掉一个顶点,任何和这个顶点相关的边都删除。

结果:分别对以上几种情况测试,测试通过。

4> public Set<L> vertices();

设计:此时可以根据图是否为空,判断当前是否会返回值,因此分为以下两种情况。

图为空

图不为空

思路、过程:根据方法上方的注释分析,返回这个图中所有的顶点。

结果:分别对以上两种情况测试,测试通过。

5> public Map<L, Integer> sources(L target);

设计:此时可以根据顶点是否在图中,顶点是否存在源顶点分区。

顶点在图中,顶点存在源顶点

顶点不在图中,顶点不存在源顶点

顶点在图中,定点不存在源顶点

顶点不在图中,顶点存在源顶点

思路、过程:根据方法上方的注释分析,获取带有指向目标顶点的边的源顶点以及这些边的权值。因此我们可以根据当前顶点是否在图中,以及定点是否存在源顶点分区。

结果:分别对以上四种情况测试,测试通过。

6> public Map<L, Integer> targets(L source);

设计:此时可以根据顶点是否在图中,顶点是否存在目标顶点分区。

顶点在图中,顶点存在目标顶点

顶点不在图中,顶点存在目标顶点

顶点在图中,顶点不存在目标顶点

顶点不在图中,顶点不存在目标顶点

思路、过程:根据方法上方的注释分析,我们需要从源顶点获得带有有向边的目标顶点以及这些边的权值。因此我们可以对当前顶点是否在图中、当前顶点是否存在目标顶点分区。

结果:分别对以上四种情况测试,测试通过。

以下截图为在实现Problem2后对Problem1进行的测试:

依次通过ConcreteEdgesGraph与ConcreteVerticesGraph实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a1tkZJPM-1624860192646)(/SoftwareConstruction/experiment2/image004.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dZMM1low-1624860192647)(/SoftwareConstruction/experiment2/image005.png)]

Problem 2: Implement Graph <String>
Implement ConcreteEdgesGraph
  • 1> Edge类:

Edge类的私有变量如下,由于Edge类的变量都是用private、final修饰,且String、Integer均为不可变类型,因此Edge类不可变:

变量意义
private final String source;边的起点
private final String target;边的终点
private final Integer weight;边的权值

Edge类的方法如下:

方法意义
public Edge(final String sourceConstruct,final String targetConstruct,final int weightConstruct)构造函数
public void checkRep()检查不变量,weight>0, source!=null, target!=null
public String getWeight ()获取边的weight值
public String getSource ()获取边的起点
public String getTarget()获取边的终点
public String toString()返回边的字符串表示
  • // Abstraction function:
  • // 从source到target,且权值为weight的有向边
  • // Representation invariant:
  • // weight>0,且source!=null,target!=null
  • // Safety from rep exposure:
  • // 使用private和final修饰变量,且使用变量的类型均为不可变类型。
  • // 避免从外部直接修改的风险。

CheckRep:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-inlaavWV-1624860192648)(/SoftwareConstruction/experiment2/image006.png)]

我们此时只需要检查this.weight>0,this.target!=null,this.source!=null,即可完成对不变量的检查。

toString:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oHZJkVAV-1624860192649)(/SoftwareConstruction/experiment2/image007.png)]

将toString函数打印方法设置如上,方便读取。

  • 2> ConcreteEdgesGraph类:

ConcreteEdgesGraph有两个私有变量:

变量意义
private final Set<String> vertices = new HashSet<>()图的所有顶点
private final List<Edge> edges = new ArrayList<>()图的所有边

ConcreteEdgesGraph的方法如下:

方法意义
public ConcreteEdgesGraph()构造函数,创建一个空图
public void checkRep()检查不变量
public boolean add(String vertex)向图中添加一个边
public int set(String source, String target, int weight)添加、该边、或删除一个图中的一个加权有向边
public boolean remove(String vertex)去掉图中的一个顶点
public Set<String> vertices()返回图中所有的顶点
public Map<String, Integer> sources(String target)返回target顶点的所有源顶点及权值的映射
public Map<String, Integer> targets(String source)返回source顶点的所有目标定点及权值的映射
public String toString()返回图的字符串表示

继承关系如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vsd39x0p-1624860192650)(/SoftwareConstruction/experiment2/image008.png)]

  • // Abstraction function:
  • // 由顶点为vertices、边为edges组成的图
  • // 即从vertices、edges到有向图的映射
  • // Representation invariant:
  • // edges.getWeight>0,且edges中不存在两条相同的边
  • // vertices中的顶点不为空
  • // Safety from rep exposure:
  • // 使用private和final修饰变量
  • // 使用防御性复制

CheckRep:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mvLW1LGJ-1624860192650)(/SoftwareConstruction/experiment2/image009.png)]

检查edges中是否存在相同的边,edges中每条边的权值是否大于,以及是否存在顶点为空的情况。

toString:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ew9dVdI5-1624860192651)(/SoftwareConstruction/experiment2/image010.png)]

将toString函数打印方法设置如上,方便读取。

  • 3> 测试策略

对ConcreteEdgesGraph类的测试策略如下:

  1. public boolean add(String vertex)
    • // Testing s* trategy for ConcreteEdgesGraph.add()
    • //
    • // Partition the inputs as follows:
    • // whether the vertex is in the vertices
    • //
    • // Exhaustive Cartesian coverage of partitions.
  2. public int set(String source, String target, int weight)
    • // Testing strategy for ConcreteEdgesGraph.set()
    • //
    • // Partition the inputs as follows:
    • // whether the edge is in the graph
    • // weight : >0 =0
    • //
    • // Exhaustive Cartesian coverage of partitions.
  3. public boolean remove(String vertex)
    • // Testing strategy for ConcreteEdgesGraph.remove()
    • //
    • // Partition the inputs as follows:
    • // whether the vertex is in the graph
    • //
    • // Exhaustive Cartesian coverage of partitions.
  4. public Set<String> vertices()
    • // Testing strategy for ConcreteEdgesGraph.vertices()
    • //
    • // Partition the inputs as follows:
    • // whether the graph is empty
    • //
    • // Exhaustive Cartesian coverage of partitions.
  5. public Map<String, Integer> sources(String target)
    • // Testing strategy for ConcreteEdgesGraph.sources()
    • //
    • // Partition the inputs as follows:
    • // whether the target has sources
    • //
    • // Exhaustive Cartesian coverage of partitions.
  6. public Map<String, Integer> targets(String source)
    • // Testing strategy for ConcreteEdgesGraph.targets()
    • //
    • // Partition the inputs as follows:
    • // whether the source has targets
    • //
    • // Exhaustive Cartesian coverage of partitions.
  7. public String toString()
    • // Testing strategy for ConcreteEdgesGraph.toString()
    • //
    • // Partition the inputs as follows:
    • // whether the graph is empty
    • //
    • // Exhaustive Cartesian coverage of partitions.

对Edge类的测试策略如下:

  1. public String getWeight ()
    • // Testing strategy for Edge.getWeight()
    • //
    • // Partition the inputs as follows:
    • // Whether the weght is null
    • //
    • // Exhaustive Cartesian coverage of partitions.
  2. public String getSource ()
    • // Testing strategy for Edge.getSource()
    • //
    • // Partition the inputs as follows:
    • // Whether the source is null
    • //
    • // Exhaustive Cartesian coverage of partitions.
  3. public String getTarget()
    • // Testing strategy for Edge.getTarget()
    • //
    • // Partition the inputs as follows:
    • // Whether the target is null
    • //
    • // Exhaustive Cartesian coverage of partitions.
  4. public String toString()
    • // Testing strategy for Edge.toString()
    • //
    • // Partition the inputs as follows:
    • // Whether the Edge is empty
    • //
    • // Exhaustive Cartesian coverage of partitions.
  • 4> 测试结果:

可以看到所有测试通过,并且,代码覆盖率为100%.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2I2hK2Mf-1624860192651)(/SoftwareConstruction/experiment2/image011.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9XVdsKL-1624860192652)(/SoftwareConstruction/experiment2/image012.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOfjee7G-1624860192652)(/SoftwareConstruction/experiment2/image013.png)]

Implement ConcreteVerticesGraph
  • 1> Vertex类:

Vertex中含有两个私有变量:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0os6Le2-1624860192652)(/SoftwareConstruction/experiment2/image014.png)]

以下为Vertex中的方法:

方法意义
public Vertex(final String VertexName);构造函数
public void checkRep();检查不变量
public boolean isEqualsVertex(Vertex vertexAnother);检查顶点的名字是否与当前顶点名字相同
public boolean isEqualsName(String vertexAnother);检查字符串是否与当前顶点名字相同
public void writeTarget(String vertexAnother, Integer weight);将有向边写入TargetEdge中
public String Name();返回当前顶点的名字
public Map<String, Integer> Target();返回当前顶点所有目标顶点及对应权值
public Integer weight(String vertexAnother);返回当前顶点所有源顶点及对应权值
public boolean remove(String vertexTarget);去除掉当前顶点的vertexTarget目标顶点
public String toString();返回图的字符串表示
  • // Abstraction function:
  • // 由顶点的名字及其对应目标顶点的映射所对应的实际顶点表示
  • // 即由String、Map组成的抽象数据类型对应的顶点
  • // Representation invariant:
  • // vertex不为空且TargetEdge中的weight>0
  • // Safety from rep exposure:
  • // 使用private、final修饰的变量
  • // 防御性复制

CheckRep:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-09cxdBSs-1624860192653)(/SoftwareConstruction/experiment2/image015.png)]

检查vertex不为空且TargetEdge中的weight>0。

toString:

将toString函数打印方法设置如上,方便读取。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Df925TLm-1624860192653)(/SoftwareConstruction/experiment2/image016.png)]

2> ConcreteVerticesGraph类:

ConcreteVerticesGraph类有一个私有变量:

变量意义
private final List<Vertex> vertices = new ArrayList<>()存储所有顶点

以下为ConcreteVerticesGraph的方法:

方法意义
public ConcreteVerticesGraph()构造函数,创建新的空的图
public void checkRep()检查不变量
public boolean add(String vertex)将顶点添加到图中
public int set(String source, Stringtarget, int weight)
public boolean remove(String vertex)从图中去掉vertex顶点
public Set<String> vertices()返回图中所有顶点的集合
public Map<String, Integer> sources(String target)返回target在图中的所有源顶点
public Map<String, Integer> targets(String source)返回source在图中的所有目标顶点
public String toString()返回图的字符串表示

继承关系如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2mtbIEb1-1624860192653)(/SoftwareConstruction/experiment2/image017.png)]

  • // Abstraction function:
  • // 由vertices组成的顶点
  • // 即由List<Vertex>类型数据到加权有向图的映射
  • // Representation invariant:
  • // vertices中不存在重复的顶点
  • // Safety from rep exposure:
  • // 使用private、final修饰变量
  • // 采用防御性复制

CheckRep:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XxR0j9dp-1624860192654)(/SoftwareConstruction/experiment2/image018.png)]

toString:

将toString函数打印方法设置如上,方便读取.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cFawmz0n-1624860192654)(/SoftwareConstruction/experiment2/image019.png)]

  • 3> 测试策略:

对ConcreteVerticesGraph的测试策略:

  1. public boolean add(String vertex)
    • // Testing strategy for ConcreteVerticesGraph.add()
    • //
    • // Partition the inputs as follows:
    • // 是否为空图: empty graph? yes 、no
    • // 当前的顶点是否在图中:whether vertex is in the graph? yes 、no
    • //
    • // Exhaustive Cartesian coverage of partitions.
  2. public int set(String source, String target, int weight)
    • // Testing strategy for ConcreteVerticesGraph.set()
    • //
    • // Partition the inputs as follows:
    • // 当前的顶点是否在图中:whether vertex is in the graph? yes 、no
    • // value of weight? =0、>0
    • // 顶点是否存在目标顶点:whether vertex has target? yes 、no
    • //
    • // Exhaustive Cartesian coverage of partitions.
  3. public boolean remove(String vertex)
    • // Testing strategy for ConcreteVerticesGraph.remove()
    • //
    • // Partition the inputs as follows:
    • // 是否为空图: empty graph? yes 、no
    • // 当前的顶点是否在图中:whether vertex is in the graph? yes 、no
    • //
    • // Exhaustive Cartesian coverage of partitions.
  4. public Set<String> vertices()
    • // Testing strategy for ConcreteVerticesGraph.vertices()
    • //
    • // Partition the inputs as follows:
    • // 是否为空图: empty graph? yes 、no
    • //
    • // Exhaustive Cartesian coverage of partitions.
  5. public Map<String, Integer> sources(String target)
    • // Testing strategy for ConcreteVerticesGraph.sources()
    • //
    • // Partition the inputs as follows:
    • // 是否为空图: empty graph? yes 、no
    • // 当前的顶点是否在图中:whether vertex is in the graph? yes 、no
    • // 顶点是否存在源顶点:whether vertex has source? yes 、no
    • //
    • // Exhaustive Cartesian coverage of partitions.
  6. public Map<String, Integer> targets(String source)
    • // Testing strategy for ConcreteVerticesGraph.targets()
    • //
    • // Partition the inputs as follows:
    • // 是否为空图: empty graph? yes 、no
    • // 当前的顶点是否在图中:whether vertex is in the graph? yes 、no
    • // 顶点是否存在目标顶点:whether vertex has target? yes 、no
    • //
    • // Exhaustive Cartesian coverage of partitions.
  7. public String toString()
    • // Testing strategy for ConcreteVerticesGraph.toString()
    • //
    • // Partition the inputs as follows:
    • // empty graph: yes 、no
    • //
    • // Exhaustive Cartesian coverage of partitions.

对Vertex类的测试策略如下:

  1. public boolean isEqualsVertex(Vertex vertexAnother)
    • // Testing strategy for Vertex.isEqualsVertex()
    • //
    • // Partition the inputs as follows:
    • // whether vertexAnother is equal to Vertex
    • //
    • // Exhaustive Cartesian coverage of partitions.
  2. public boolean isEqualsName(String vertexAnother)
    • // Testing strategy for Vertex.isEqualsName()
    • //
    • // Partition the inputs as follows:
    • // whether vertexAnother’s name is equal to Vertex
    • //
    • // Exhaustive Cartesian coverage of partitions.
  3. public void writeTarget(String vertexAnother, Integer weight)
    • // Testing strategy for Vertex.writeTarget()
    • //
    • // Partition the inputs as follows:
    • // whether vertexAnother is in the TargetEdge
    • // weight:>0 =0
    • //
    • // Exhaustive Cartesian coverage of partitions.
  4. public String Name()
    • // Testing strategy for Vertex.Name()
    • //
    • // whether Vertex is null
    • //
    • // Exhaustive Cartesian coverage of partitions.
  5. public Map<String, Integer> Target()
    • // Testing strategy for Vertex.Target()
    • //
    • // Partition the inputs as follows:
    • // wherger TargetEdge is null
    • //
    • // Exhaustive Cartesian coverage of partitions.
  6. public Integer weight(String vertexAnother)
    • // Testing strategy for Vertex.weight()
    • //
    • // Partition the inputs as follows:
    • // whether vertexAnother is in the TargetEdge
    • //
    • // Exhaustive Cartesian coverage of partitions.
  7. public boolean remove(String vertexTarget)
    • // Testing strategy for Vertex.remove()
    • //
    • // Partition the inputs as follows:
    • // vertexTarget is in the TargetEdge or not
    • //
    • // Exhaustive Cartesian coverage of partitions.
  8. public String toString()
    • // Testing strategy for Vertex.toString()
    • //
    • // Partition the inputs as follows:
    • // vertex is null or not
    • //
    • // Exhaustive Cartesian coverage of partitions.
  • 4> 测试结果

可以看到测试全部通过,且代码覆盖率为100%:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sHGKJCS5-1624860192654)(/SoftwareConstruction/experiment2/image020.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JRVpYSrT-1624860192655)(/SoftwareConstruction/experiment2/image021.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-maHaGzNR-1624860192655)(/SoftwareConstruction/experiment2/image022.png)]

Problem 3: Implement generic Graph<L>
Make the implementations generic

此时具体类的声明如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eeDdIZiq-1624860192656)(/SoftwareConstruction/experiment2/image023.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mVSW6C10-1624860192656)(/SoftwareConstruction/experiment2/image024.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4kdUFuN4-1624860192656)(/SoftwareConstruction/experiment2/image025.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sk5hcqHC-1624860192657)(/SoftwareConstruction/experiment2/image026.png)]

并对problem2部分实现的功能修改,使其支持泛型。

将ConcreteEdgesGraph及ConcreteVerticesGraph中部分用String声明的变量修改为L,并且在声明类的时候,使用泛型L。

实现后具体类的修改后,对其测试,发现测试全部通过。且覆盖率仍为100%

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j52SpnRW-1624860192657)(/SoftwareConstruction/experiment2/image027.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3XIEBufd-1624860192657)(/SoftwareConstruction/experiment2/image028.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rLyGsfwN-1624860192658)(/SoftwareConstruction/experiment2/image029.png)]

Implement Graph.empty()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWWfDjln-1624860192658)(/SoftwareConstruction/experiment2/image030.png)]

此处选择ConcreteEdgesGraph或ConcreteVerticesGraph中的一个。

为了确保支持不同的类型,分别测试两种不同的类型Integer、Charater。

分别对不同的类型对实现的方法测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MpRyWaG5-1624860192658)(/SoftwareConstruction/experiment2/image031.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-361IFTBU-1624860192659)(/SoftwareConstruction/experiment2/image032.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ui97GoFu-1624860192659)(/SoftwareConstruction/experiment2/image033.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ooRH4cwZ-1624860192659)(/SoftwareConstruction/experiment2/image034.png)]

如图,此时测试覆盖率为100%.

Problem 4: Poetic walks
Test GraphPoet

对GraphPoet类的测试如下:

  1. public GraphPoet(File corpus)
    • // Testing strategy for the constructor of GraphPoet
    • // Testing strategy for GraphPoet.toString()
    • // Partition the inputs as follows:
    • // whether the corpus is not exist
    • // whether the corpus is a empty file
    • //
    • // Exhaustive Cartesian coverage of partitions.
  2. public String poem(String input)
    • // Testing strategy for GraphPoet.poem()
    • //
    • // Partition the inputs as follows:
    • // Whether the input has the same edge
    • //
    • // Exhaustive Cartesian coverage of partitions.
  3. public String toString()
    • // Testing strategy for the constructor of GraphPoet
    • // Testing strategy for GraphPoet.toString()
    • // Partition the inputs as follows:
    • // whether the corpus is not exist
    • // whether the corpus is a empty file

在完成下一单元后,对其测试,测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGSqE1fx-1624860192660)(/SoftwareConstruction/experiment2/image035.png)]

可以看到,此时覆盖率为百分值百:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFHnRpwb-1624860192660)(/SoftwareConstruction/experiment2/image036.png)]

对部分测试策略分析:
当输入文件为下方文件时:
> To explore to explore interesting new interesting explore interesting explore strange new worlds
> To seek out new life and new civilizations and civilizations and

此时graph如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9X9nJswK-1624860192660)(/SoftwareConstruction/experiment2/image037.png)]

当我们的输入语句为Seek to explore new and exciting synergies!时,此时对应的语句应该为Seek to explore interesting new civilizations and exciting synergies!
当此时输入文件为下方字符时:

> To explore strange new worlds
> To seek out new life and new civilizations

此时graph如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4TSie2Y8-1624860192661)(/SoftwareConstruction/experiment2/image038.png)]

当我们的输入语句为Seek to explore new and exciting synergies!时,此时对应的语句应该为Seek to explore strange new life and exciting synergies!

Implement GraphPoet
    1. public GraphPoet(File corpus)

首先是文件的读取,采用System.getProperty(“user.dir”)的函数读取当前工作区,并加上路径,读取出所需的文件。

再通过BufferedReader、FileReader将文件读取到一个字符串中,再通过split函数,将所有空格消除,并读取到List中,再通过List中的removeAll函数,将所有的空字符串删除,此时即可得到文件中所有的单词,并保存到一个列表中。

依次对所有的单词遍历,若前一个节点及后一个节点都在图中,且weight++,否则令weight=1.

    1. public String poem(String input)

首先将input的输入通过split函数,切分为每个单词,并通过与GraphPoet相似的方法,获得单词的列表,此时我们用List中的顺序,每次取出第i个,及第i+1,如果第i个单词及第i+1个单词之间在图中存在别的单词连接,则将这个单词放到StringBuilder中。直到结束后,将最后一个单词也放进,并加上感叹号。

具体结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L5NtMrAK-1624860192661)(/SoftwareConstruction/experiment2/image039.png)]

Graph poetry slam

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L7Sfl741-1624860192661)(/SoftwareConstruction/experiment2/image040.png)]

对于如图所示的main函数,由于输入的文件为:
> This is a test of the Mugar Omni Theater sound system.

因此在test与the中间存在of单词,因此输出结果应该为:Test of the system!

通过测试,所得结果与预期一致,完成预期要求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pEVeOsaO-1624860192662)(/SoftwareConstruction/experiment2/image041.png)]

使用Eclemma检查测试的代码覆盖度

由于IDE采用IntelliJ IDEA 2020.3.1,此处使用IDEA内置的使用覆盖率测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hjGhGI34-1624860192662)(/SoftwareConstruction/experiment2/image042.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnKZGE3b-1624860192663)(/SoftwareConstruction/experiment2/image043.png)]

可以看到此时覆盖率为100%。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bFOzXkZj-1624860192663)(/SoftwareConstruction/experiment2/image044.png)]

将工作区复制到Ecilipse中,用Eclemma检测覆盖率,此时覆盖率仍然大约为95%左右。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SfI07bF-1624860192663)(/SoftwareConstruction/experiment2/image045.png)]

Before you’re done

通过Git提交当前版本到GitHub上你的Lab2仓库。

git add .
git commit -m "P1"
git push

项目的目录结构树状示意图如下方所示:
此处采用linux中的tree命令.

Re-implement the Social Network in Lab1

FriendshipGraph类
  • 1.FriendshipGraph类有一个私有变量:
    private Graph<Person> graph = Graph.empty();
  • 2.FriendshipGraph类的方法如下:
方法意义
public void checkRep()检查不变量
public boolean addVertex(Person person)添加顶点
public boolean addEdge(Person person1,Person person2)添加边
public int getDistance(Person person1,Person person2)返回从person1到person2的距离

关系图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oy2krM45-1624860192664)(/SoftwareConstruction/experiment2/image046.png)]

  • // Abstraction function:
  • // 由Graph<Person> graph对应的图
  • // Representation invariant:
  • // graph中所有边的weight=0或=1,且顶点名字不为空
  • // Safety from rep exposure:
  • // 使用private、final修饰的变量
  • // 防御性复制

checkRep如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CSRjHWGp-1624860192664)(/SoftwareConstruction/experiment2/image047.png)]

getDistance的实现如下:

  • 1.将person1保存到HashSet<Person> Search中;
  • 2.将person1认识的人保存到HashSet<Person> Search_Next中;
  • 3.将Search和Search_Next都保存到新的HashSet<Person> Search_assist中;
  • 4.初始化distance = 1;
  • 5.若Search_Next中含有person2,返回distance,即为所求距离。否则将Search清空,将Search_Next保存到Search中,在将Search中所有的人认识的人的HashSet中所有的元素添加到Search_Next,再将Search_Next中所有在Search_assist中保存的元素消除掉,再将所有Search_Next元素添加到Search_assist中。此时distance++;
  • 6.重复步骤5,若Search_Next最终为空,则不存在距离,返回值为-1;否则,person1与person2之间存在路径,且 person1与person2距离为distance。
Person类
    1. Person类有一个私有变量:

private final String name;

    1. FriendshipGraph类的方法如下:
方法意义
public Person(String personName)构造函数
public void checkRep()检查不变量
public String getName()返回当前Person的姓名
  • // Abstraction function:
  • // 由String name对应的Person
  • // Representation invariant:
  • // name不为空
  • // Safety from rep exposure:
  • // 使用private、final修饰的变量
  • // 防御性复制

checkRep如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r6U8gTrR-1624860192664)(/SoftwareConstruction/experiment2/image048.png)]

客户端main()

此处将重新利用Lab1中main客户端,由于对addVertex、addEdge、getDistance该函数均已完成,因此此处重新利用即可。
运行发现,与预期结果一致。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s7xbhhdo-1624860192665)(/SoftwareConstruction/experiment2/image049.png)]

测试用例

对于FriendshipGraph类:

  1. 测试策略:

1.1 public boolean addVertex(Person person)

  • // Testing strategy for GraphPoet.addVertex()
  • //
  • // Partition the inputs as follows:
  • // Whether the grapg is empty
  • //
  • // Exhaustive Cartesian coverage of partitions.

1.2 public boolean addEdge(Person person1,Person person2)

  • // Testing strategy for GraphPoet.addVertex()
  • //
  • // Partition the inputs as follows:
  • // Whether the edge is in the graph
  • //
  • // Exhaustive Cartesian coverage of partitions.
    1.3 public int getDistance(Person person1,Person person2)
  • // Testing strategy for GraphPoet.getDistance()
  • //
  • // Partition the inputs as follows:
  • // Is it possible to go from A to B
  • //
  • // Exhaustive Cartesian coverage of partitions.
  1. 测试结果

    此处主要说明对getDistance的测试,其余部分详见代码。
    通过以下的图,对getDistance测试:
    由图可得,ben 与 a 的距离为 2,ben 与 kramer 的距离为 3,b 与 kramer的距离为 2,kramer 与 rachel 的距离为 5。
    并进行测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bZ6L1QaA-1624860192665)(/SoftwareConstruction/experiment2/image050.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-56mQwnF1-1624860192666)(/SoftwareConstruction/experiment2/image051.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kownst5I-1624860192666)(/SoftwareConstruction/experiment2/image052.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUF4zSDw-1624860192666)(/SoftwareConstruction/experiment2/image053.png)]

可以发现,此时测试全部通过测试,并且代码覆盖率为100%.

对于Person类:

  1. 测试策略
  • // Testing strategy for Person.getName
  • //
  • // Partition the inputs as follows:
  • // whether Person is null
  • //
  • // Exhaustive Cartesian coverage of partitions.
  1. 测试结果

测试全部通过,并且代码覆盖率100%。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AlVm82Jk-1624860192667)(/SoftwareConstruction/experiment2/image054.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FxPlFyIW-1624860192667)(/SoftwareConstruction/experiment2/image055.png)]

提交至Git仓库

如何通过Git提交当前版本到GitHub上你的Lab2仓库。
在这里给出你的项目的目录结构树状示意图。

git add .
git commit -m "P2"
git push

目录结构树状示意图如下所示:

此处采用linux中的tree命令.

实验过程中遇到的困难与解决途径

遇到的难点解决途径
泛型的转换最初理解起来稍有问难。通过查阅资料并与同学讨论等途径解决。
对于题目某些部分理解起来稍有困难。通过自己耐心探究解决。
测试策略的设计。通过查阅相关资料并加以体会解决。

实验过程中收获的经验、教训、感想

  • 1.掌握了在测试中,写出测试策略,并根据此设计测试用例的方法
  • 2.了解了OOP实现ADT,并对RI、REP、AF等有了更深的了解
  • 3.对于整个过程了解更加深刻
  • 4.掌握了ADT设计的基本方法
  • 5.了解了ADT的泛型化
  • 6.意识到避免表示泄露的重要性,并在实践中,践行了保护的过程

针对以下方面的感受

(1) 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?

在面向ADT的编程设计,我们往往要考虑程序的功能、应用场景以及复用性,使编出的程序更加灵活;而面向应用场景编程,适用范围较小,但可以根据具体场景,灵活编程。

(2) 使用泛型和不使用泛型的编程,对你来说有何差异?

使用泛型可以更改数据类型,如P2可以以Person为数据类型,在初次接触时有一些不适应,但很快便了解并掌握。泛型为程序的复用性带来了很大帮助,并且使类型更加安全。

(3) 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?

先完成测试用例的编写能够让我更好的理解规格说明。规格说明也可能存在问题–不正确、不完整、模棱两可、确实边界情况。 因此先尝试编写测试用例,可以在我浪费时间实现一个有问题的规格说明之前发现这些问题。因此我能够适应这种测试方式。

(4) P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?

避免重复实现具有类似功能的ADT,将已有代码进行复用,不仅在一定程度上节约了时间,同时还能进一步保证程序的正确性,避免写类似代码时,犯更多的错误。同时还能够锻炼我们的抽象能力,在实现ADT时候,充分考虑应用场景。

(5) P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?

实验未要求P3.

(6) 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?

表示暴露影响程序的安全运行,同时影响到不变性和表示独立性处理表示暴露避免类内部数据被从外部访问。并且在编程时候在抽象类型表示声明后写上对于抽象函数和表示不变量的注解,可以便于读取表示不变量、抽象域的表示、规定合法的表示值如何被解释到抽象域。方便程序员的处理。以后也会坚持这个习惯。

(7) 关于本实验的工作量、难度、deadline。

本实验工作量较大,尤其是编写测试时,耗费时间较长,难度可以接受,deadline比较合理。

(8) 《软件构造》课程进展到目前,你对该课程有何体会和建议?

使我对软件构造有了新的感悟,一方面对程序的测试分区等有了新的体会,另一方面,对规范的注释等有了新的了解,另一方面更加体会到了面向对象编程,除此之外,更加了解了如何保证程序的安全运行。
建议,对PPT内容扩充,方便同学们复习。
序的复用性带来了很大帮助,并且使类型更加安全。

(3) 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?

先完成测试用例的编写能够让我更好的理解规格说明。规格说明也可能存在问题–不正确、不完整、模棱两可、确实边界情况。 因此先尝试编写测试用例,可以在我浪费时间实现一个有问题的规格说明之前发现这些问题。因此我能够适应这种测试方式。

(4) P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?

避免重复实现具有类似功能的ADT,将已有代码进行复用,不仅在一定程度上节约了时间,同时还能进一步保证程序的正确性,避免写类似代码时,犯更多的错误。同时还能够锻炼我们的抽象能力,在实现ADT时候,充分考虑应用场景。

(5) P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?

实验未要求P3.

(6) 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?

表示暴露影响程序的安全运行,同时影响到不变性和表示独立性处理表示暴露避免类内部数据被从外部访问。并且在编程时候在抽象类型表示声明后写上对于抽象函数和表示不变量的注解,可以便于读取表示不变量、抽象域的表示、规定合法的表示值如何被解释到抽象域。方便程序员的处理。以后也会坚持这个习惯。

(7) 关于本实验的工作量、难度、deadline。

本实验工作量较大,尤其是编写测试时,耗费时间较长,难度可以接受,deadline比较合理。

(8) 《软件构造》课程进展到目前,你对该课程有何体会和建议?

使我对软件构造有了新的感悟,一方面对程序的测试分区等有了新的体会,另一方面,对规范的注释等有了新的了解,另一方面更加体会到了面向对象编程,除此之外,更加了解了如何保证程序的安全运行。
建议,对PPT内容扩充,方便同学们复习。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: RT-LAB软件是一个实时仿真平台,用于开发和测试各种电力系统和控制系统。RT-LAB软件培训旨在帮助个人和团队掌握使用该平台进行仿真和实时测试的技能。 RT-LAB软件培训涵盖了从基础知识到高级技术的全面内容。首先,培训将介绍RT-LAB软件的基本原理和功能,包括其架构、界面和主要工具。参与者将了解如何在软件中创模型、配置仿真参数和观察仿真结果。 在培训的进一步阶段,参与者将深入学习RT-LAB软件的高级功能,如实时系统模和控制算法设计。培训还将介绍如何使用RT-LAB软件进行硬件在环仿真,将虚拟模型与实际硬件进行连接和测试。 培训期间,参与者将有机会通过实际案例和实践项目来应用所学知识。他们将学习如何使用RT-LAB软件解决电力系统和控制系统的实际问题,并进一步优化系统性能。 RT-LAB软件培训还提供了与专业导师和其他参与者进行交流和讨论的机会。参与者可以分享经验、学习最佳实践,并获取来自行业专家的指导。 通过参加RT-LAB软件培训,个人和团队可以充分利用该软件平台的优势,提高仿真和测试的效率和准确性。这将有助于加快产品开发和测试周期,并为电力系统和控制系统的设计和优化提供更好的支持。 ### 回答2: RT-LAB 是一种实时仿真软件平台,广泛应用于电力系统、机械系统、汽车系统和航空航天等领域的研究和开发中。对于那些需要进行实时仿真和控制系统开发的工程师和科研人员来说,接受RT-LAB软件培训是非常有益和必要的。 RT-LAB软件培训可以帮助学员掌握RT-LAB软件的基本原理和使用方法。培训内容通常包括软件架构、模和仿真技术、实时控制算法的设计和实现以及硬件接口和数据采集等方面的知识。学员将通过理论讲解和实际操作来学习和运用软件的各种功能和工具。 参加RT-LAB软件培训的好处有很多。首先,培训可以帮助学员快速上手并熟练使用RT-LAB软件,提升工作效率。其次,培训可以帮助学员深入了解软件的各项功能和应用场景,从而更好地应用于实际工程项目中。另外,培训还可以提供实时仿真和控制系统设计的相关知识和技巧,为学员在相关领域的研究和开发中提供支持和指导。此外,培训还可以帮助学员立良好的团队合作和沟通能力,与其他专业人员进行有效的合作和交流。 总之,RT-LAB软件培训对于想要在实时仿真和控制系统开发领域有所树的工程师和科研人员来说是非常重要的。通过培训,学员可以快速掌握软件的使用方法,提升工作效率并应用于实际工程项目中。同时,培训还可以提供相关知识和技巧,帮助学员在研究和开发中取得更好的成果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值