本次实验训练抽象数据类型(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并据此设计测试用例。
延续Lab1中的实验环境,除此之外,本次实验在 Eclipse IDE中安装配置 EclEmma(一个用于统计JUnit测试用例的代码覆盖度测试用例的代码覆盖度plugin)
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号):
https://github.com/ComputerScienceHIT/Lab2-1173710111
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)
(1)首先分别构造两个实例类的rep类Vertex和Edge;
(2)用String作为L的特例,分别在两个实例类中实现Graph接口中的各个方法,写对应的test文件以确保其正确性;
(3)将所有String变量替换为泛型L。
2. 对给定的文本文件,按照给定规则建立有向图,调用Graph
请阅读 http://web.mit.edu/6.031/www/sp17/psets/ps2/,遵循该页面内的要求完 ,遵循该页面内的要求完成编程任务。
⚫ 在 Get the code步骤中你无法连接MIT的 Athena服务器,请从以下地址获取初始代码 :
https://github.com/rainywang/Spring2019_HITCS_SC_Lab2/tree/master/P1
⚫ 在作业描述中若遇到 “commit and push”的要求 ,请将你的代码 push到你的 GitHub Lab2仓库中 。
⚫ 其他步骤请遵循 MIT。
自 https://github.com/rainywang/Spring2019_HITCS_SC_Lab2/tree/master/P1 获得实验代码。
git初始化:
Git init
Git remote add origin [email protected]:ComputerScienceHIT/Lab2-1173710111.git
Git pull origin master
Git add .
Git commit -m “xxx”
Git push origin master
静态 Graph.empty()方法的测试策略和测试都在GraphStaticTest.java,为了运行这个测试,首先要修改Graph
public static String Graph empty() {
Graph graph = new ConcreteEdgesGraph();
return graph;
}
这里以ConcreteEdgesGraph作为Graph默认的实例类,也可以用ConcreteVerticesGraph,二者是等价的
(1)实现 Edge<String>类
private int weight; |
边的权值 |
private String sourceVertex; |
边的起点 |
private String targetVertex; |
边的终点 |
public Edge(L source,L target,int w){ this.weight=w; this.sourceVertex=source; this.targetVertex=target; }
|
getter |
三个域的getter,因为规定Edge |
public void checkRep() { assert sourceVertex!=null; assert targetVertex!=null; assert weight>=0; } |
每个getter返回前检查该边的起点、终点、权值是否有空的。 |
@Override public String toString() |
以字符串的形式直观地展示该边的起点、终点和边权,格式为: source->target [weight] |
(2)实现ConcreteEdgesGraph类
private final Set<String> vertices |
保存图中的所有顶点 |
private final List |
顺序存储图中的所有边 |
每个function返回前检查rep不变 private void checkRep() { for(int i=0;i<edges.size();i++) { assert vertices.contains(edges.get(i).getSourceVertex()):"an edge with illegal vertex"; assert vertices.contains(edges.get(i).getTargetVertex()):"an edge with illegal vertex"; for(int j=i+1;j<edges.size();j++) { assert !(edges.get(i).getSourceVertex().equals(edges.get(j).getSourceVertex())&&edges.get(i).getTargetVertex().equals(edges.get(j).getTargetVertex())) :"duplicate edges"; } assert edges.get(i)!=null; } for(L s:vertices) { assert s!=null; } } |
|
@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),调用Collections.replaceAll替换掉edges中的旧边,返回旧边权; (2)如果不存在,新建一条边(参数为source,target,weight),将其加入edges,返回0。 |
@Override public boolean remove(L vertex) |
调用set.contains判断图中是否存在该顶点:(1)如果不存在,返回false;
|
@Override public Set |
copy一份vertices到新Set中,返回这个Set |
@Override public Map |
建立一个空Map,遍历edges,找出以target为终点的边edge; weight=0时表示该边不存在,跳过; 将edge.source->edge.weight加入Map,遍历结束后返回这个Map |
@Override public Map |
建立一个空Map,遍历edges,找出以source为起点的边edge; weight=0时表示该边不存在,跳过; 将edge.source->edge.weight加入Map,遍历结束后返回这个Map |
@Override public String toString() |
将所有边的toString连接在一起 |
(3)编写测试 GraphInstanceTest.java
public abstract Graph |
抽象方法,创建新的空Graph |
@Test public void testAdd() |
分别对input未存在、已存在的情况进行测试,检查其rep是否与期待相符 |
@Test public void testRemove() |
|
@Test public void testSources() |
1. 参数vertex的source域为空; 2. 参数vertex的target域为空; 3. 对set方法传入weight=0的情况进行测试
方法调用后,对相关参数(边)调用source方法或target方法的返回值进行检查 |
@Test public void testTargets() |
|
@Test public void testSet() |
方法调用后,对相关参数(边)调用source方法或target方法的返回值进行检查 |
@Test public void testVertices() |
调用add和remove方法,然后对vertices方法的返回值进行检查 |
@Test public void testALL() |
创建一个较复杂的有向图,调用到每个方法,对rep进行检查 |
(4)编写测试ConcreteEdgesGraphTest.java
Graph中定义的接口 |
GraphInstanceTest.java中实现,不必重复 |
创建一个新的空图 ConcreteEdgesGraph @Override public Graph return new ConcreteEdgesGraph }
|
|
public void testToString() |
调用Graph中的方法构建一张有向图,测试toString的返回值是否能正确规范地表示这张图。 |
public void testVertex() |
主要测试Edge中的toString方法,测试其返回值能否正确规范地表示这条边的信息。 |
(1)实现Vertex
private L name; |
当前节点的名字(标签) |
private Map |
存储所有以当前点为终点的边,key表示边的起点,value表示边权 |
private Map |
存储所有以当前点为起点的边,key表示边的终点,value表示边权 |
public Vertex(L name){ this.name=name; } |
setter |
source,target的setter |
getter |
name,source,target的getter |
public void checkRep() { assert source!=null; assert target!=null; assert name!=null; } |
每个getter返回前检查当前点的rep是否非空。 |
@Override public String toString() |
以字符串的形式直观地展示有哪些边以当前点为终点\起点,格式为: {[source,weight], ...}->{[target,weight], ...} |
(2)实现ConcreteVertices类
private final List |
存储图的顶点 |
每个function返回前检查rep不变 private void checkRep(){ for(int i=0;i<vertices.size();i++) { for(int j=i+1;j<vertices.size();j++) { assert !(vertices.get(i).getName().equals(vertices.get(j).getName())) :"duplicate vertices"; } assert vertices.get(i)!=null; } for(Vertex assert s!=null; } } |
|
@Override public boolean add(L vertex) |
遍历vertices:
|
@Override public int set(L source, L target, int weight) |
(1)先调用add加入两个顶点; (2)首先遍历vertices,找到标签与source相等的顶点vertex,然后遍历该顶点的vertex.target,找到标签与target相等的顶点,获取对应的边权,然后更新边权为weight,返回旧边权; (3)在(2)中如果没有找到标签与target相等的顶点,则遍历vertices进行寻找,如果找到了,建立target->weight的映射并加入vertex.target,返回0。 |
@Override public boolean remove(L vertex) |
|
@Override public Set |
copy一份vertices到新Set中,返回这个Set |
@Override public Map |
建立一个空Map,遍历vertices,如果某个vertex其vertex.target不为空并且包含了target,就建立vertex->vertex.weight的映射并加入Map; weight=0时表示该边不存在,跳过; 遍历结束后返回Map |
@Override public Map |
建立一个空Map,遍历vertices,如果某个vertex其vertex.source不为空并且包含了source,就建立vertex->vertex.weight的映射并加入Map; weight=0时表示该边不存在,跳过; 遍历结束后返回Map |
@Override public String toString() |
将所有点的toString连接在一起 |
(3)编写测试ConcreteVerticesGraphTest.java
Graph中定义的接口 |
GraphInstanceTest.java中实现,不必重复 |
创建一个新的空图ConcreteVerticesGraph @Override public Graph return new ConcreteVerticesGraph } |
|
public void testToString() |
调用Graph中的方法构建一张有向图,测试toString的返回值是否能正确规范地表示这张图。 |
public void testVertex() |
主要测试Vertex中的toString方法,测试其返回值能否正确规范地表示这个顶点的信息。 |
将两个实例类中的所有String类的参数替换为泛型
修改Graph.empty为:
public static
Graph
return graph;
}
这里以ConcreteEdgesGraph作为Graph
语料库文件配置为:new File("src/P1/poet/mugar-omni-theater.txt") |
文本为:This is a test of the Mugar Omni Theater sound system. |
@Test public void testGraphPoet() throws IOException { final GraphPoet nimoy = new GraphPoet(new File("src/P1/poet/mugar-omni-theater.txt")); final String input = "Test the system."; assertEquals("Test of the system.",nimoy.poem(input)); } |
rep:
private Graph |
用于存储文本文件读入后按规则建立的有向图 |
constructor:
public GraphPoet(File corpus) throws IOException |
根据参数(文件),判断能否正常读入(否则抛出异常),并且调用poemGraph(corpus)方法创建好语料库(有向图) |
function:
public void checkRep() { assert !corpusGraph.vertices().isEmpty(); } |
各方法返回前检查rep不为空 |
public Graph |
根据参数(文件)创建语料库,规则为:相邻两个单词直接建立一条权值为1的有向边,有重复边时权值+1。 首先将文件以字符串形式读入,按“ ”(空格)划分为各个单词,不区分大小写,然后线性扫描,调用corpusGraph.set()建边 |
public String poem(String input) |
对input进行扩展,规则是:如果相邻两个单词a和b,在语料库中存在一个单词c使a->c和c->b都存在,则将c插入a和b之间;如果存在多个满足条件的c,取边权a->c较大的。 首先将input按“ ”(空格)划分为各个单词,不区分大小写,线性扫描,调用corpusGraph.target()和source()找出所有可能的“桥”(上面说到的c),然后找到边权最大的一个,插入。最后返回扩展好的字符串。 |
public String toString() |
return corpusGraph.toString(); |
更新语料库文件中的字符串和输入的字符串input
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库:
Git add .
Git commit -m “xxx”
Git push origin master
在这里给出你的项目的目录结构树状示意图。
项目名称:Lab2-1173710111
|
继承P1中ConcreteEdgesGraph
public void addVertex(Person person) |
遍历父类的vertices(),如果存在一个元素的name域与Person的name域相等,证明这个点已经存在,输出提示,否则调用父类的add(person)将该点加入 |
public void addEdge(Person p1, Person p2) |
先调用父类的set(p1,p2,1),如果返回值为0证明这两个点之间不存在边,否则证明这两个点之间已经有边存在,输出提示 |
public int getDistance(Person p1, Person p2) |
使用BFS算法求p1与p2之间的最短距离,BFS需要遍历邻居节点时调用父类接口的targets(p1)就可以获得p1的所有邻居节点。 |
public Set |
copy一份vertices,存储图中所有的顶点,即关系网络中的所有人。 |
public static void main(String Args[]) |
与Lab1相同 |
由于继承了ConcreteVerticesGraph |
public class Person { private String name; public boolean vis=false;
public Person(String name) { this.name=name; } public String getName() { return this.name; } } |
Lab1实验手册给出。
public void addVertexTest() |
测试重名点 |
public void addEdgeTest() |
测试重边 |
public void getdistance() |
测试非连通点和两个相同点 |
如何通过Git提交当前版本到GitHub上你的Lab3仓库。
Git add .
Git commit -m “xxx”
Git push origin master
在这里给出你的项目的目录结构树状示意图。
|
设计了哪些ADT(接口、类),各自的rep和实现,各自的mutability/ immutability说明、AF、RI、safety from rep exposure。描述你设计的各ADT间的关系。
坐标类:定义一个点(棋子)的坐标位置,并且提供判重方法
rep:
private int x; |
横纵坐标 |
private int x; |
constructor:
public Position(int x,int y) { this.x=x; this.y=y; } |
function:
public void setPosition(int x,int y) |
修改横纵坐标 |
public int getPositionX() |
获取横纵坐标 |
public int getPositionY() |
|
public boolean equals(Position that) |
判断两个Position相等 |
2. Piece(mutable)
棋子类:定义一个棋子,包括棋子所属的游戏类型(围棋/象棋),棋子类型(黑白/将相车卒等),棋子状态(未放置,待放置,已移除);
rep:
//player1,player2 final private String belong; |
棋子属于哪个玩家,不可变 |
final private String type; |
棋子的类型,不可变 围棋有“black”“white”两种,国际象棋有很多种(兵”P”、王”K”、后”Q”等) |
//0-unplaced,1-placed,2-removed. private int pieceState; |
棋子的状态,可变 0-unplaced,1-placed,2-removed |
private Position piecePosition; |
棋子在棋盘上的位置,可变 |
constructor:
public Piece(String belong,String type) { this.belong=belong; this.type=type; } |
function:
setter |
state和piecePositon有对应的getter |
getter |
四个域都有getter,piecePosition的getter有两个,分别返回横纵坐标 |
3. Player(mutable)
玩家类,包括玩家的基本信息,以及玩家所拥有的棋子信息。
rep:
final private String name; |
玩家的名字,不可更改 |
private Set |
存储玩家拥有的所有棋子 |
private List |
顺序保存玩家在一局游戏里的走棋历史 |
constructor:
public Player(String name) { this.name=name; } |
function:
getter |
三个域的getter |
public boolean addPiece(Piece newPiece) |
添加一枚棋子,已经拥有返回false,否则添加并返回true |
public boolean removePiece(Piece removePiece) |
移除一枚棋子,不存在返回false,否则移除并返回true |
public int getNumberOfPieces() |
获取棋盘上属于自己的棋子数,即统计自己的棋子里pieceState为1的棋子数 |
public void addStep(String step) |
向historyList域中添加一个走棋步骤 |
4. Board(mutable)
定义一个名为“棋盘”的类,在这个类里定义了棋盘的规格,并生成一个空的棋盘。 规格:由一个正整数n决定的一个n*n的正方形
rep:
final private int type; |
棋盘的类型: 0 means the pieces are placed in blanks[0,n-1], 1 means the pieces are placed on points[0,n]. |
final private int size; |
棋盘的大小,size*size |
private Piece[][] pieces; |
存储棋盘的某个位置上放置的棋子 |
private boolean[][] placed; |
判断棋盘上的某个位置是否放置了棋子 |
constructor:
public Board(int type,int size) { this.type=type; this.size=size; size+=type; //根据size的大小初始化两个二维数组 pieces=new Piece[size][size]; placed=new boolean[size][size]; //初始化,棋盘最初是空的 for (int i=0;i<size;i++) { for (int j=0;j<size;j++) placed[i][j]=false; } } |
function:
getter |
type和size的getter |
public Piece getPiece(int x,int y) |
给出一对横纵坐标,获取该位置上的棋子,如果没有,返回的为空,因此需要在客户端进行判断 |
public boolean setPiece(Piece p,int x,int y) |
在位置(x,y)上放置piece |
public void setPlaced(int x,int y) |
将(x,y)对应的Placed状态置为true/false |
public void setNotPlaced(int x,int y) |
|
public boolean getPlaced(int x,int y) |
获取(x,y)对应位置是否放置了棋子 |
5. Action(interface)
提供棋类游戏各种行为的接口
public static Action empty(String gameType) |
根据输入的字符串判断以哪一个实例类作为默认的实现 |
public Player createPlayer1(String playerName1); |
创建两个玩家 |
public Player createPlayer2(String playerName2); |
|
public Board board(); |
创建一个新的空棋盘 |
public void initialize() |
* 初始化,包括: * 1。设置相关参数 * 2。生成一个棋盘并初始化 * 3。生成一组棋子 * 4。给定两个名称,初始化两个Player对象 * 5。将棋子分配给两个Player对象 |
public boolean placePiece(Player player,Piece piece,int x,int y); |
* 给定“棋手、一颗棋子、指定位置的横坐标、指定位置的纵坐标”作为输入参数,将该棋手的该颗棋子放置在棋盘上 *异常情况,例如:该棋子并非属于该棋手、指定的位置超出棋盘的范围、指定位置已有棋子、所指定的棋子已经在棋盘上等,返回false * 否则,将棋子落在指定位置,返回true |
public boolean movePiece(Player player,int sx,int sy,int tx,int ty);
|
* 给定“棋手、初始位置和目的位置的横纵坐标”,将处于初始位置的棋子移动到目的位置。 * 需要考虑处理各种异常情况,例如: * 指定的位置超出棋盘的范围、目的地已有其他棋子、初始位置尚无可移动的棋子、两个位置相同、初始位置的棋子并非该棋手所有等,返回false * 否则,将处于初始位置的棋子移动到目的位置,返回true。 |
public boolean removePiece(Player player,int x,int y);
|
* 给定“棋手、一个位置的横纵坐标”,将该位置上的对手棋子移除。 * 需要考虑处理异常情况,例如:该位置超出棋盘的范围、该位置无棋子可提、所提棋子不是对方棋子、等,返回false。 * 否则,移除棋子并返回true。 |
public boolean eatPiece(Player player,int sx,int sy,int tx,int ty);
|
* 给定“棋手、两个位置横纵坐标”,将第一个位置上的棋子移动至第二个位置,第二个位置上原有的对手棋子从棋盘上移除。 * 需要处理异常情况,例如: * 指定的位置超出棋盘的范围、第一个位置上无棋子、第二个位置上无棋子、两个位置相同、第一个位置上的棋子不是自己的棋子、第二个位置上的棋子不是对方棋子、等. * 返回false。 * 否则,返回true。 |
有两个实例类:ChessAction和GoAction
(1)ChessAction
因为国际象棋中没有落子和提子的行为,所以客户端并不允许调用placePiece和removePiece,这两个接口在实现时返回值永远为false。
rep:
final protected static int boardsize=8; |
棋盘大小,国际象棋棋盘大小为8*8 |
final protected static int piecesize=32; |
棋子总个数,国际象棋初始时棋子最多共32个 |
protected Player player1; |
调用createPlayer1和createPlayer2创建两个Player |
protected Player player2; |
|
protected Board chessBoard=new Board(0, boardsize); |
新建一个规格为8*8的棋盘 |
(2)GoAction
因为围棋中没有移子吃子的行为,所以客户端并不允许调用movePiece和eatPiece,这两个接口在实现时返回值永远为false。
rep:
final protected static int boardsize=18; |
棋盘大小,围棋棋盘大小为19*19 |
final protected static int piecesize=361; |
棋子总个数,围棋棋盘上最多有361个位置可以放置棋子 |
protected Player player1; |
调用createPlayer1和createPlayer2创建两个Player |
protected Player player2; |
|
protected Board chessBoard=new Board(0, boardsize); |
新建一个规格为19*19的棋盘 |
6. Game(immutable)
这是一个游戏类,用来创建一个棋盘游戏,并提供所有可能使用的功能。
rep:
private Action gameAction; |
创建一个新的棋类Action |
private Player player1; |
两个玩家 |
private Player player2; |
|
private Board board; |
棋盘 |
constructor:
给定游戏类型,两个玩家的名字,创建一个新的Game |
public Game(String game,String playerName1,String playerName2) { gameAction=Action.empty(game); player1=gameAction.createPlayer1(playerName1); player2=gameAction.createPlayer2(playerName2); gameAction.initialize(); board=gameAction.board(); } |
function:
public int getBoardSize() |
1.get the size of board;
|
public String getPlayer1() |
2.get the names of two players;
|
public String getPlayer2() |
|
public boolean placePiece(String playerName,int x,int y) |
3.achieve some kinds of behavior of board games, such as falling, lifting, moving and eating pieces. *输入非法时输出提示并返回false,否则返回true |
public boolean movePiece(String playerName,int sx,int sy,int tx,int ty) |
|
public boolean removePiece(String playerName,int x,int y) |
|
public boolean eatPiece(String playerName,int sx,int sy,int tx,int ty) |
|
public boolean checkBoardPlaced(int x,int y) |
4.given a position,check the state of this position on board,whether is occupied or not,if occupied,occupied by whose which pieces.
|
public int getNuberOfPiece(String playerName) |
5.calculate the numbers of the two players' pieces.
|
public String getHistorySteps(String playerName) |
6.given a player’s name ,output the history of this game in this competition.
|
辅之以执行过程的截图,介绍主程序的设计和实现方案,特别是如何将用户在命令行输入的指令映射到各ADT的具体方法的执行。
(1)主程序入口
public static void main(String[] args) { new MyChessAndGoGame().gameMain(); } |
(2)主函数
public void gameMain() { Scanner in=new Scanner(System.in); String gameType; while(true) { System.out.println("******************"); System.out.println("*欢迎来到不正经棋牌室!*"); System.out.println("******************"); System.out.println("请选择想要创建的棋类游戏:"); System.out.println("1. 国际象棋"+"\t"+"2. 围棋"); int p=in.nextInt(); if (p==1) { gameType=new String("chess"); in.nextLine(); break; }else { if (p==2) { gameType=new String("go"); in.nextLine(); break; }else { continue; } } } System.out.println("请输入玩家1的名字:"); String playerName1; playerName1=in.nextLine(); System.out.println("请输入玩家2的名字:"); String playerName2; playerName2=in.nextLine(); //调用Game类创建了一盘新的棋类游戏 Game game=new Game(gameType, playerName1, playerName2); if (gameType.contentEquals("chess")) { //根据选择的棋类游戏,分别调用函数继续 startChessGame(game); }else { startGoGame(game); } in.close(); } |
(3)以围棋为例,进行游戏的函数:
public void startGoGame(Game game) { while(true) { //玩家1先手: System.out.println("棋盘的大小为:"+game.getBoardSize()+"*"+game.getBoardSize()); printGoMenu(); System.out.print("玩家 "+game.getPlayer1()+" 请输入选项:"); Scanner in=new Scanner(System.in); String choice=in.nextLine(); //根据选择、进行行动的玩家名,继续下面的行为: chooseOfGo(game, choice,game.getPlayer1(),in); System.out.println(); if (choice.equals("end")) in.close();
//玩家2后手: System.out.println("棋盘的大小为:"+game.getBoardSize()+"*"+game.getBoardSize()); printGoMenu(); System.out.print("玩家 "+game.getPlayer2()+" 请输入选项:"); String choice2=in.nextLine(); chooseOfGo(game, choice2,game.getPlayer2(),in); System.out.println(); if (choice.equals("end")) in.close(); } } |
(4)根据不同选项进行不同操作的函数:
public void chooseOfGo(Game game,String choice,String playerName,Scanner in) { int x=0,y=0; switch (choice) { case "1": do{ System.out.println("请输入落子位置的横纵坐标(x,y):"); try { String xyString=in.nextLine(); String[] xy=xyString.split(","); x=Integer.valueOf(xy[0]); y=Integer.valueOf(xy[1]); }catch (Exception e) { // TODO: handle exception e.getStackTrace(); } }while (!game.placePiece(playerName, x, y)); break; case "2": do{ System.out.println("请输入提子位置的横纵坐标(x,y):"); try { String xyString=in.nextLine(); String[] xy=xyString.split(","); x=Integer.valueOf(xy[0]); y=Integer.valueOf(xy[1]); }catch (Exception e) { // TODO: handle exception e.getStackTrace(); } }while(!game.removePiece(playerName, x, y)); break; case "3": System.out.println("请输入想要查询的位置的横纵坐标(x y):"); String xyString=in.nextLine(); String[] xy=xyString.split(","); x=Integer.valueOf(xy[0]); y=Integer.valueOf(xy[1]); game.checkBoardPlaced(x, y); System.out.println("棋盘的大小为:"+game.getBoardSize()+"*"+game.getBoardSize()); printGoMenu(); System.out.print("玩家 "+playerName+" 请输入选项:"); choice=in.nextLine(); chooseOfGo(game,choice,playerName,in); break; case "4": System.out.println("玩家 "+game.getPlayer1()+" 在棋盘上的棋子总数为:"+game.getNuberOfPiece(game.getPlayer1())); System.out.println("玩家 "+game.getPlayer2()+" 在棋盘上的棋子总数为:"+game.getNuberOfPiece(game.getPlayer2())); System.out.println("棋盘的大小为:"+game.getBoardSize()+"*"+game.getBoardSize()); printGoMenu(); System.out.print("玩家 "+playerName+" 请输入选项:"); choice=in.nextLine(); chooseOfGo(game,choice,playerName,in); break; case "5": extracted(); break; case "end": System.out.println("玩家"+game.getPlayer1()+"的走棋历史:"); System.out.println(game.getHistorySteps(game.getPlayer1())); System.out.println("玩家"+game.getPlayer2()+"的走棋历史:"); System.out.println(game.getHistorySteps(game.getPlayer2())); System.out.print("欢迎下次再来!"); System.exit(0); break; default: System.out.println("输入错误,请重新输入:"); choice=in.nextLine(); chooseOfGo(game,choice,playerName,in); } } private void extracted() { return; } |
(5)以国际象棋为例,程序运行截图如下:
介绍针对各ADT的各方法的测试方案和testing strategy。
介绍你如何对该应用进行测试用例的设计,以及具体的测试过程。
public Action emptyInstance();
|
/** * Overridden by implementation-specific test classes. * * @return a new empty Action of the particular implementation being tested */
|
public void testCreatePlayers();
|
/** * test whether the action create two right players. */
|
public void testInitialize();
|
/** * Overridden by implementation-specific test classes. * Check every position on the board, and pieces, for proper initialization. */
|
public void testPlacePiece();
|
/** * Overridden by ChessActionTest. * place a piece on a specific position,and check whether the state is right. * test every illegal input. * test some legal input,and check the state of player,board,and piece after placePiece. */ |
public void testMovePiece(); |
/** * Overridden by ChessActionTest. * move a piece from a specific position to another,and check whether the state is right. * test every illegal input. * test some legal input,and check the state of player,board,and piece after movePiece. */
|
public void testRemovePiece(); |
/** * Overridden by ChessActionTest. * remove a piece from a specific position,and check whether the state is right. * test every illegal input. * test some legal input,and check the state of player,board,and piece after removePiece. */
|
public void testEatPiece(); |
/** * Overridden by ChessActionTest. * use a piece from a specific position to eat another,and check whether the state is right. * test every illegal input. * test some legal input,and check the state of player,board,and piece after eatPiece. */ |
rep:
private Game chessGame; |
private Game goGame; |
function:
@Before public void initialize(){ chessGame=new Game("chess","ChessPlayer1", "ChessPlayer2"); goGame=new Game("go","GoPlayer1", "GoPlayer2"); } |
|
@Test public void testPlacePiece() |
/** * test some illegal input. * test some legal input,and check the state of player,board after placePiece,and the return value. */ |
@Test public void testMovePiece() |
/** * test some illegal input. * test some legal input,and check the state of player,board after movePiece,and the return value. */ |
@Test public void testRemovePiece() |
/** * test some illegal input. * test some legal input,and check the state of player,board after removePiece,and the return value. */ |
@Test public void testEatPiece() |
/** * test some illegal input. * test some legal input,and check the state of player,board after eatPiece,and the return value. */ |
@Test public void testGetGistorySteps_Go() |
/** * make some steps,and then test the output of getHistorySteps */ |
@Test public void testGetGistorySteps_Chess() |
/**
* test some methods of Player,Board,Piece,Position
*/
rep:
Board board; |
Player player; |
List |
function:
@Before public void initialize() { board=new Board(0, 5); player=new Player("player"); List<Piece> pieces=new ArrayList<Piece>(); for (int i=0;i<10;i++) { Piece piece=new Piece("player", "1"); pieces.add(piece); } } |
|
@Test public void testPlayer() |
test player.getHistory() |
@Test public void testPosition() |
test position.equals() |