Lab2摘要
有关代码的截图不再提供,仅发布设计思路:
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实验环境配置
IDE采用eclipse,之前已经配置完成
Jdk使用jdk8
GitHub Lab1仓库URL地址:
https://github.com/ComputerScienceHIT/Lab2-1180300528
3实验过程
3.1Poetic Walks
进一步认识ADT,通过任务学习泛型,测试泛型,通过实现的泛型设计poet。
3.1.1Get the code and prepare Git repository
https://github.com/rainywang/Spring2019_HITCS_SC_Lab2/tree/master/P1
下载P1文件夹,获取任务代码
本地创建git仓库
建立文件夹,用git bush 打开,输入git init
和远程仓库建立连接
git add 添加到暂存区
git commit 提交到git仓库
git push 同步到远程仓库
3.1.2Problem 1: Test Graph
testAdd:测试添加点是否成功添加,并且添加已经添加的点返回false
testSet:
添加点已经存在的边,并观察其返回值是否为该边之前的权重
添加点不存在的边,观察边以及原先不存在的点是否以及添加
testRemove:
首先观察添加的边是否存在
然后删除一个顶点
观察相关边和点是否被删除
然后观察删除点已经删除的点时是否返回false
testVertices:在图中添加一些点,以观察图中是否有并且只有这些点
先添加一些点:
观察顶点集是否与已添加点集相同
testSources:
先建立一个图,
来测试没有源点的点的源集是否为空集
有源点的点源点集是否满足要求(包括相关的源点和相应元素的权重是否正确)
testTargets:建立一个图,来测试没有目标点的点的目标集是否为空集, 有目标点的点的目标点集是否符合要求(包括相关目标点及对应元素权重是否正确)
测试代码基本与testSources相同,这里不再叙述。
3.1.3Problem 2: Implement Graph
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
3.1.3.1Implement ConcreteEdgesGraph
3.1.3.1.1 ConcreteEdgesGraph:
// Abstraction function:
//由边和顶点组成的ADT到有向图的映射
// Representation invariant:
//边的权重必须大于等于0
//边与边之间不能相等
// Safety from rep exposure:
//设置private final ,使用防御性拷贝以及使用Collections.unmodifiableMap()等
private final Set vertices = new HashSet<>();
private final List<Edge> edges = new ArrayList<>();
分别存放图中的点以及边;
public boolean add(L vertex):将点添加到点集合中;
如果已经包含该边则进行checkrep()检查返回false;
如果不包含则将其添加到点集合中并进行checkrep()检查返回true;
public int set(L source, L target, int weight):添加或者设置一条边
首先在边集合中查找对应的边,如果对应的边存在(源点目标点相同):
获取该边权重赋值给preweight,移除该边;
然后判断新权重是否大于0,如果大于0则创建边并加入到边集合;
进行checkrep()检查,返回preweight;
如果没有找到该边,如果权重大于0;
将不存在点集合中的点添加到点集合中,再添加边到边集合,checkrep()检查并返回0;
如果权重等于0且未找到,则checkrep()检查并返回0;
public boolean remove(L vertex)移除一个点以及对应边
首先判断图中是否有该点,若没有直接返回false;
采用Iterator迭代器,因为在遍历边集时要删除集合内元素(如果某一条边的一个端点与该点相同),接下来再在点集合内删除该点;
最后checkrep()检查并返回true;
public Set vertices()返回点集合
先创建一个集合,将点复制到该集合中;
再返回不可更改的set:
public Map<L, Integer> sources(L target)返回源点集合
首先创建一个map,以源点以及对应权重为键值对;
遍历edges寻找满足条件的点加入map;
返回不可更改的map:
public Map<L, Integer> targets(L source)
与sources类似,这里不再叙述;
public String toString()
为空时返回提示信息;
不为空时利用StringBuilder连接字符串;
3.1.3.1.2 Edge:
// Abstraction function:
//由源点、目标点、权重到有向边的映射
// Representation invariant:
//source != null,target != null,weight >= 0,源点与目标点不相等
// Safety from rep exposure:
//设置private final
private final L source;
private final L target;
private final int weight;
分别存放边的源点、目标点以及权重;
提供类的构造函数三个变量的get方法以及toStrring方法;
构造函数内调用checkrep()检查;
将边输出为方便读取的形式:
3.1.3.1.3ConcreteEdgesGraphTest:
ConcreteEdgesGraph补充测试toString:
Edge类只测试toString,其他类方法仅为get方法较为简单无需测试;
3.1.3.2Implement ConcreteVerticesGraph
3.1.3.1.1ConcreteVerticesGraph:
// Abstraction function:
//顶点构成的ADT到有向图的映射
// Representation invariant:
//顶点间彼此不能相等
// Safety from rep exposure:
//设置 private final,使用防御性拷贝,使用Collections.unmodifiableMap()等
private final List<Vertex> vertices = new ArrayList<>();
存放图中顶点集合;
public boolean add(L vertex)
如果顶点集里该点已存在,则抛出异常,捕获后返回false;
否则建立新的顶点并添加到顶点集合,进行checkrep()检查并返回true;
public int set(L source, L target, int weight)
先在顶点集合里寻找两个端点;
如果没有找到源点则添加源点,进行checkrep()检查;
若目标点未找到则进行相同操作;
接下来如果新weight>0,则调用Vertex类的方法设置边,并得到preweight;
否则相当于删除这一条边;
最后进行checkrep()检查并返回preweight;
public boolean remove(L vertex)
遍历点集找到要删除的顶点,如果找到了则再遍历顶点如果要删除点的源点集或者目标点集里有该点,则将要删除的点从该点的源点集或目标点集中删去;
接下来从图的点集中删去要删除的顶点,进行checrep()检查并返回true;
如果没找到,则进行checrep()检查并返回false;
public Set vertices()
先建立一个set,遍历点集合复制到set内;
返回一个不可更改的set;
public Map<L, Integer> sources(L target)
建立一个map,遍历顶点,如果找到对应点则将对应点的不可更改的源点集合赋值给map;
返回一个不可更改的map;
public Map<L, Integer> targets(L source)
与sources类似
public String toString()
首先判断点集合是否为空,若空则返回提示信息;
若不空,则遍历点集合,用StringBuilder连接字符串;
3.1.3.1.2Vertex:
// Abstraction function:
//由一个顶点的标签,该点的源点以及该点的目标点组成的ADT到有向图顶点的映射
// Representation invariant:
//权重必须大于等于0
//顶点不能和他的源点或者目标点相同
// Safety from rep exposure:
//设置 private final,使用防御性拷贝,使用Collections.unmodifiableMap()等
private final L thisVertex;
private final Map<L,Integer> sources = new HashMap<>();
private final Map<L,Integer> targets = new HashMap<>();
分别存放点的标记,该点的<源点,权重>Map以及该点的<目标点,权重>Map;
public Map<L,Integer> getSources()
首先创建一个map,遍历sources,将内容复制到新map里;
返回不可更改的map
public Map<L,Integer> getTargets()
与getSources类似;
public int setSource(L source,int weight)
weight小于0时输出错误提示信息返回0;
遍历该点的sources,寻找符合要求的源点;
如果找到对应点之后,先获取该点对应的权重;
再删除该键值对;
如果新的weight>0则建立新的键值对添加的源点map内;
checkrep()检查并返回preweight;
如果没有找到:
如果weigt>0则添加新的键值对;
然后checkrep()检查并返回0
public int setTarget(L target,int weight)
与setSource类似
public int removeSource(L source)
遍历源点集合,如果找到对应点则记录权重,删除该源点,进行checkrep()检查并返回preweight;
如果未找到,则输出提示信息,进行checkrep()检查并返回0;
public int removeTarget(L target)
与removeSource类似
public String toString()
采用StringBuilder连接字符串;
如果源点集合为空,输出提示信息:
如果不为空则遍历并添加字符串:
对于目标点集同样操作这里不再叙述;
3.1.3.1.3ConcreteEdgesGraphTest:
ConcreteVerticesGraph补充测试toString:
Vertex类:
test_SetSource_and_getSources:
设置顶点的源点和相应边的权重,观察返回值是否正确;
观察getSources的返回值是否包含且仅包含添加的源点;
testSetTarget_and_getTargets:
设置顶点的目标点和相应边的权重,观察返回值是否正确;
观察getTargets的返回值是否包含且仅包含添加的目标点;
与test_SetSource_and_getSources基本相同这里不再叙述;
test_removeSource:
删除现有的源点和不存在的源点,并观察返回值是否正确
test_removeTarget:
删除现有目标点和不存在的目标点,观察返回值是否正确
与test_removeSource基本类似,不再叙述;
test_edge_toString:判断输出结果是否与特定字符串相同
没有边时:
设置边之后:
测试结果:
3.1.4Problem 3: Implement generic Graph
3.1.4.1Make the implementations generic
进行修改,将ADT修改为泛型,以ConcreteEdgesGraph的部分内容为示例:
3.1.4.2Implement Graph.empty()
对于其他不可变类型的测试,这里的其他不可变类型选取Integer;
这里展示两个方法的测试,对于其他类型的测试与String大同小异,这里不再赘述;
详细内容参看源代码;
3.1.5Problem 4: Poetic walks
3.1.5.1Test GraphPoet
// Testing strategy
//测试语料库内有多行文字
//测试toString
与图中测试类似,这里不再叙述
//测试简单句子
//测试特殊情况(大小写,非法字符,优先选择权重高的词添加)
语料库:
测试结果:
3.1.5.2Implement GraphPoet
// Abstraction function:
//使用加权有向图找出两点之间是否有桥梁进而向句子中添加中间词
// Representation invariant:
//图不能为空
// Safety from rep exposure:
//设置private final 使用防御性拷贝
3.1.5.2.1 GraphPoet(File corpus) throws IOException
将语料库按行读入到字符串数组中保存:
将按行读入的字符串利用空格进行分割,并将其转换为小写:
将边和点添加到图中,并且获取某条边set之前的权重,如果不为0,则将其set为原先的权重加一:
3.1.5.2.2 public String poem(String input)
首先将要作诗的字符串按空格进行分割:
用StringBuilder连接新生成的字符串;
遍历字符串,在图中寻找有没有连接两点的桥梁;
如果两点不包含在图中,则添加空字符串:
接下来寻找权重最高的桥梁,首先先找到在语料库构成的图中与某个作诗单词相连且为目标点的节点,获得这条边的权重:
再寻找以这个节点为源点,以下一个作诗单词为目标点的权重最高的边:
接下来判断这一桥梁的权重是否为最大权重,如果是则更新最大权重以及桥梁节点:
遍历结束后,添加最优的桥梁节点:
最后添加下一个作诗单词:
继续下一轮遍历知道将作诗字符串中的单词全部添加到新的字符串。
结果:
3.1.5.3Graph poetry slam
得到一句较为完整的话句:
3.1.6Before you’re done
3.2Re-implement the Social Network in Lab1
完成Person和FriendshipGraph两个类,模拟社交网络,能够实现添加节点、节点之间添加边的功能,并且可以计算两节点之间最短路
3.2.1FriendshipGraph类
// Abstraction function:
//从顶点与顶点之间的边到有向关系图的一个映射
// Representation invariant:
//graph != null
// Safety from rep exposure:
//set private final
采用基于点的图
private final Graph graph = new ConcreteVerticesGraph<>();
3.2.1.1public boolean addVertex(Person person)
利用图的add方法,将点加入图中,并根据返回值判断是否加入成功,如果失败输出提示信息;
3.2.1.2public boolean addEdge(Person p1, Person p2)
根据graph的set方法添加边,若该边已经存在set方法返回权重,所以可根据返回值是否为0判断该边是否已经存在进而输出提示信息;
3.2.1.3public int getDistance(Person p1, Person p2)
先判断是否为自身到自身的边,如果是,返回0
采用广度优先搜索,定义相关的变量
对每个要加入队列的元素先进行初始化,设置到目标点距离为0,被访问标记设置为未被访问,然后对队列初始化,将起始点加入队列,设置访问标记为true
队列不空则每次取出队首元素,获得与其相连的元素,如果该元素未被访问则将访问标记修改为true并添加到队列尾;更新距离为当前点与起始点距离为已删去队首元素的距离加一;
如果有点元素与目标点相等,则返回;
如果经过遍历之后并未发现目标点,则说明两点不连通,返回-1
3.2.2Person类
// Abstraction function:
//从姓名到人(person)的一个映射
// Representation invariant:
//name != null
// Safety from rep exposure:
//set private final
因为在P1的Graph基础上再次编写FriendshipGraph,因此Person类相对于Lab1删去了一些不必要的内容并增加了对equals以及Hashcode的覆写。
仅保存该person的名字;实现Constructor以及getter方法;
覆写equals、hashcode、toString方法
hashcode以及toString不在这里给出。
3.2.3客户端main()
客户端依旧采用Lab1给出的客户端
执行结果:
3.2.4测试用例
测试策略:
addVertexTest:
测试添加不同Person节点是否成功以及重复添加已添加的节点是否失败
addEdgeTest:
测试添加不同节点的之间的边以及两节点间反向边是否成功
测试重复添加已存在边是否失败
getDistanceTest:
测试自身到自身的距离是否正确
测试当两节点间只有单向联通的边时两个节点不同方向的距离是否正确
测试当两节点间有双向联通的边时两个节点不同方向的距离是否正确
测试不直接相连节点间距离是否为最短距离
测试结果:
3.2.5提交至Git仓库
采用git push origin master提交到github远程仓库
3.3Playing Chess
3.3.1ADT设计/实现方案
设计了哪些ADT(接口、类),各自的rep和实现,各自的mutability/ immutability说明、AF、RI、safety from rep exposure。
必要时请使用UML class diagram(请自学)描述你设计的各ADT间的关系。
3.1.1.1 Color
immutability
辅助保存棋子颜色;
3.1.1.2 State
immutability
辅助保存棋子状态
3.1.1.3 Piece
immutability
// Abstraction function:
//从棋子名称、颜色、状态到一个棋子的映射
// Representation invariant:
//名字,颜色,状态不为空
//名字符合棋子命名规范
// Safety from rep exposure:
//set private final
private final String PieceName;
private final Color PieceColor;
private State PieceState;
分别保存棋子的名字,颜色,状态
提供对这个三个变量的get方法
同时覆写equals方法以及hashcode方法
3.1.1.4 Position
immutability
// Abstraction function:
//从x,y坐标到点的映射
// Representation invariant:
//(Integer)x,y != null
// Safety from rep exposure:
//set private
private int x;
private int y;
提供对x,y坐标的get方法以及覆写equals和hashcode方法
3.1.1.5 Player
mutability
// Abstraction function:
//从姓名、所持棋子颜色、下棋历史到棋手的一个映射
// Representation invariant:
//名字、所持棋子的颜色、历史 不等于 null
// Safety from rep exposure:
//set private final
private final String PlayerName;
存放玩家名字;
private final Color PlayerColor;
存放玩家所持有的棋子的颜色;
private String History = “”;
存放玩家的操作历史;
构造函数:
提供变量的get方法;
public void addHistory(String oneHistory)
添加玩家历史;
public boolean judgeOwnPiece(Piece piece)
通过比较棋子颜色判断玩家是否拥有棋子piece;
3.1.1.6 Board
mutability
// Abstraction function:
//从棋子的二维数组与棋盘大小到游戏棋盘的一个映射
// Representation invariant:
//BoardSize == 8 || BoardSize == 19
//BoardPosition != null
// Safety from rep exposure:
//set private final 防御性拷贝
private final int BoardSize;
private final Piece[][] BoardPosition;
存放棋盘大小以及棋盘上的棋子;
构造函数中设置棋盘大小,并对二维数组初始化:
获得某位置上的棋子:public Piece getBoardPiece(Position position)
认为位置参数合法并采用防御性拷贝;
将某棋子放在某位置:public void setBoardPosition(Piece piece,Position position)
认为输入的参数均为合法参数。
改变某位置棋子状态public void setBoardPositionState(Position position,State newState):
public void moveBoardPiece(Position position,Position newposition) :
将某个位置的棋子移动到另一个位置,认为输入的参数均为合法参数;
删除某个位置的棋子:public void deleteBoardPiece(Position position)
观察某个位置是否有棋子:public boolean whetherNull(Position position)
计算某种颜色的棋子个数public int numberOnBoard(Color color):
遍历二维数组寻找符合颜色要求且在棋盘上的棋子数目;
3.1.1.7 Action
immutability
3.1.1.7.1 Action父类
// Abstraction function:
//从用户输入到在棋盘上的棋类操作的一个映射
// Representation invariant:
//无rep不存在表示泄露
// Safety from rep exposure:
//无rep不存在rep保护
public boolean putPiece(Board board,Player player,Piece piece,Position position)
将棋子放置在指定的位置;
如果piece并非属于player、position超出棋盘的范围、piece已经在棋盘上、position处已有棋子,返回false;
特殊情况处理之后不再赘述;
对于正确情况:添加玩家历史并进行相应操作:将该棋子放置在棋盘上并修改棋子状态为EXIST;
其他三种操作分别在子类中实现,父类里仅进行声明。
3.1.1.7.2 ChessAction
public boolean movePiece(Board board,Player player,Position oldPosition,Position newPosition)
将棋子移动到指定的位置;
如果piece并非属于player、piece不在棋盘上、newposition超出棋盘的范围、newposition处已有棋子,返回false
特殊情况处理不再赘述;
对于正确情况:添加玩家历史并进行相应操作:将棋子移动到新位置,将旧位置处棋盘的棋子删除;
public boolean eatPiece(Board board,Player player_active,Player player_passive,Position position_active,
Position position_passive)
吃子
如果position1、position2超出棋盘的范围、两个位置相同、position1上无棋子、position2上无棋子、position1上的棋子不是player的棋子、第二个位置上的棋子不是对方棋子,返回false
特殊情况处理不再赘述;
对于正确情况:添加玩家历史并进行相应操作:将被吃棋子remove,将主动方的棋子移动到为被吃棋子的位置,将主动方原棋子位置的棋子删除。
3.1.1.7.3 GoAction
public boolean removePiece(Board board,
Player player_active,Player player_passive,Position position)
移除对方的且在棋盘上的棋子
如果position超出棋盘的范围、position处无棋子可提、所提piece不是对方棋子,返回false
特殊情况处理不再赘述;
对于正确情况:添加玩家历史并进行相应操作:通过设置棋子状态为REMOVE表明该棋子被移除;
这里如果棋子是通过移除操作被从棋盘拿掉则设置状态为remove,对于其他情况拿掉棋子比如在象棋里比如移动子则在棋盘上删除棋子,而对于象棋棋中的吃子,被吃子因为等同于被移除所以也设置为REMOVE,以此区分两种情况以便于将来进一步完善棋类功能。
3.1.1.8 Game
mutability
3.1.1.8.1 Game抽象类
// Abstraction function:
//从棋盘(Board),棋子(Piece),操作(Action),玩家(Player)到一场棋类游戏(Game) 的映射
// Representation invariant:
//棋盘,操作,玩家不为空
// Safety from rep exposure:
//set private
定义选手进行游戏时的轮转方法;
申明子类要实现的功能;
3.1.1.8.2 ChessGame
private final int size = 8;
private final Board chessBoard = new Board(size);
private final Action chessAction = new ChessAction();
private final Player playerW;
private final Player playerB;
构造函数:
public ChessGame(String playerWname,String playerBname)
初始化游戏的玩家:
对棋盘初始化,将双方32个棋子放在指定位置;
截取部分作为展示;
public void printBoard():打印当前棋盘情况;
public void play(Scanner scanner)
采用do while循环对玩家的输入进行相应的实现:
首先打印菜单,提示用户输入相关命令,为输入简单,用户只需要输入命令前的数字即可;
然后以1.move为例:
首先输出提示信息指导用户输入坐标;
如果用户输入不合法,在action方法中会输出错误提示信息;
然后通过轮转this.getTurn()?playerB:playerW自动确定当前的玩家;
接着调用action中的move方法进行移动;
接下来通过this.setTurn()更新轮转;
最后打印最新的棋盘;
对于2.eat,基本与move类似这里不再叙述,具体请参见代码实现;
对于3.pass:调用轮转设置方法进行一次玩家转换即可;
对于4.search:先检查该位置是否为空,若不空输出该位置棋子的相关信息;
对于5.piece number:调用board的numberOnBoard()方法即可,参数为玩家对应的棋子颜色;
对于6.History,7.PrintBoard只是简单调用方法,实现打印该玩家历史与当前棋盘即可;
对于end指令:
打印玩家历史后设置sign==false;并以此退出循环:
对于错误输入,输出相关提示信息:
结束后询问用户是否打印玩家的操作历史:
3.1.1.8.3 GoGame
与ChessGame区别在于构造函数以及menu以及相关具体实现不同,实现的方式大同小异,这里不再赘述;
构造函数仅初始化棋手;
menu菜单实现如下:
3.3.2主程序MyChessAndGoGame设计/实现方案
辅之以执行过程的截图,介绍主程序的设计和实现方案,特别是如何将用户在命令行输入的指令映射到各ADT的具体方法的执行。
对于主程序,首先定义游戏玩家Player以及游戏Game;
因为scanner的共享原因,所以将其作为参数传入稍后的Game.play();
主体采用do-while循环:
首先询问用户创建国际象棋(chess)还是围棋(go)还是选择退出程序(quit):
如果输入quit:
然后根据sign选择退出程序;
如果输入chess或者go:
输入两个玩家的姓名;
创建对应的Game;
接下来输出开始游戏的信息:
这时候调用play()方法开始对用户的输入进行分析并映射到相应的操作;
接下来对程序示例进行讲解:
输入go开始围棋游戏,接下来输入两个玩家的名字,然后输出游戏开始的提示信息,打印出菜单供用户进行输入选择:
用户输入1选择放置(put)棋子;
接下来输出提示信息,提示用户输入放置棋子的位置;
输入结束后会打印已放置棋子的棋盘,坐标以及位置采用实验要求的表现方式;
在Game里的play方法中调用Action的putpiece方法以及轮转方法(在上文3.1.1.8.2中已经详细介绍了play方法);
接下来每种操作只说明实现情况,对于每种操作的实现已在play()方法里说明,这里不再重复叙述。
此时玩家也已经发生了轮转:
接下来用户为玩家Player_White输入放置棋子坐标,效果如图:
接下来为Player_Black输入3,选择pass,此时简单输出当前棋盘并轮转:
接下来为Player_White输入2选择remove对方某个棋子:
如果输入的棋子位置不满足要求(如棋子并非对方棋子)则打印错误提示信息,输出棋盘,并进行轮转:
如果输入满足要求,则将对应位置棋子移除:
用户输入4选择查询:
如果输入位置有棋子则输出棋子信息,否则输出提示信息:
对于1,2,3操作会进行玩家轮转,其他操作不进行玩家轮转;
用户输入5选择输出当前棋盘上该玩家棋子数目:
用户输入6选择输出当前玩家历史:
其中W表示白棋white,B表示黑棋black
用户输入7打印棋盘,这一操作不再截图;
用户输入8选择结束,此时选择是否打印玩家历史,并开始下一次游戏选择:
如果输入quit则输出提示信息结束程序:
运行程序以围棋为例,国际象棋与此类似。
3.3.2ADT和主程序的测试方案
Testing strategy
对大部分类而言功能简单无需测试,只测试Action方法,并通过这些方法测试其他类功能是否完成
3.3.3.1test_putPiece:
对position超出棋盘的范围测试:
分别测试x,y超出范围:
对piece并非属于player测试:
先提供与棋手所持棋子颜色不一样的棋子,返回false,提供一样颜色后返回true
对piece已经在棋盘上测试:
将棋子状态设置为EXIST表明已在棋盘上,返回false,改为UNEXIST返回true
对position处已有棋子情况测试:
建立一个新棋子,将其放置到上面测试时已放置棋子的位置,返回false
对正确情况测试:
3.3.3.2test_movePiece:
对oldposition和newposition超出棋盘的范围测试:
对piece并非属于player测试:
通过board的相关方法进行模拟棋盘状态的预先设置,再测试该情况,测试后恢复棋盘情况;
对piece不在棋盘上测试:
然后后进行结果检查:
对newposition处已有棋子测试:
先测试已有棋子情况返回false,再测试移动目标位置没有棋子返回true
然后进行结果测试:
3.3.3.3test_removePiece:
对position超出棋盘的范围:
对position处无棋子可提:
所提棋子位置无棋子返回false
对所提piece不是对方棋子测试:
对正确情况测试:
测试正确提子情况,并通过获得棋子状态方法再次检查
3.3.3.4test_eatPiece:
对position1、position2超出棋盘的范围:
对两个位置相同测试:
对position1上无棋子、position2上无棋子测试:
先对两个位置都无棋子测试,返回false,
然后依次添加两个棋子进行测试,全部添加后返回true
然后对测试结果调用方法进行进一步验证:
对第二个位置上的棋子不是对方棋子测试:
对第一个位置上不是自己棋子,第二个位置不是对方棋子测试:
第一步初始化棋子;
第二步分别测试第二个位置上的棋子不是对方棋子;第一个位置上不是自己棋子,第二个位置不是对方棋子,返回false
第三步测试正确对应情况下返回true;
第四步根据其他方法对结果进行进一步验证,判断吃子是否成功;
测试结果:
因为Action内有子类方法的声明,所以未完全覆盖