软件构造课程心得——软件构造实验二(Lab2)

软件构造课程心得——Lab2

1. 实验目标概述

本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象 编程(OOP)技术实现 ADT。具体来说:

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

2. 实验过程

2.1 Poetic Walks

该任务主要是对图这一数据结构进行两种实现——一种是记录点和点之间的边来构成图,另一种是通过记录点集来构成图。实现后对其功能进行测试,再利用写出的图数据结构来对句子进行处理,即为所谓的Poetic Walks,通过给定的语料来对给出的句子进行拓展。

2.1.1 Get the code and prepare Git repository

通过给出的如下的网址下载所需的代码,使用git的clone功能在本地创建git仓库。https://github.com/rainywang/Spring2020_HITCS_SC_Lab2/tree/master/P1

2.1.2 Problem 1: Test Graph < String >
2.1.2.1 运行GraphStaticTest.java

将Graph.java中的empty()方法补全为如下:

public static <String> Graph<String> empty() {

	return new ConcreteEdgesGraph<String>();
	
}

建立Graph接口的工厂方法,返回一个Graph的实现类(ConcreteEdgesGraph和ConcreteVerticesGraph等价)。

随后运行GraphStaticTest.java

2.1.2.2 为ConcreteEdgesGraph.java以及ConcreteVerticesGraph.java编写测试方法

由于ConcreteEdgesGraph和ConcreteVerticesGraph是Graph的两个不同实现类,这两个类的测试方法在GraphInstanceTest.java中,用来对图数据结构的操作进行测试,两种实现应该能够通过同样的测试方法,而两种实现方法中特有的Edge类和Vertex类的测试应当分别放在ConcreteEdgesGraph.java和ConcreteVerticesGraph.java中。测试类按照前面文章中写到的完成即可。

Graph<L>的测试放在文件GraphInstanceTest.java中
Edge<L>的测试放在文件ConcreteEdgesGraph.java中
Vertex<L>的测试放在文件ConcreteVerticesGraph.java中
2.1.3 Problem 2: Implement Graph < String >
2.1.3.1 Implement ConcreteEdgesGraph

ConcreteEdgesGraph是基于边集的Graph实现。

首先实现Edge类。Edge类的实现如下:

rep:

private final String source;			边的起始顶点

private final String target; 			边的目标顶点

private final int weight;          		边的权值


method:

public Edge(L source, L target, int weight)	建立边的constructor

public String getSource()   			获得该边的起点

public String getTarget()   			获得该边的终点

public int getWeight()     			获得该边的权值

public String toString()     			将该边的信息转化成String

有了Edge类就可以进一步实现ConcreteEdgesGraph了。ConcreteEdgesGraph类的实现如下:

rep:

private final Set<String> vertices = new HashSet<>() 		该Graph的点集

private final List<Edge> edges = new ArrayList<>()   		该Graph的边集 


method:

public boolean add(String vertex)				向点集中加入新的点。

public int set(String source, String target, int weight)	遍历边集,如果存在一条从source到target的边,则将权值设为weight,返回旧
								的权值,如果要将权值设为0则删除这条边,如果不存在从source到target的边,
								则新建这样一条边并返回0.
							
public boolean remove(String vertex)				移除vertex顶点,并删去与其关联的所有边。点集中确实有vertex点并移除成功
								返回true,否则返回false。
							
public Set<String> vertices()					返回点集。

public Map<String, Integer> sources(String target)		返回将target点作为终点的所有边,将起点和权值加入到Map中返回。

public Map<String, Integer> targets(String source)		返回将source点作为起点的所有边,将终点和权值加入到Map中返回。

public String toString()					将图的信息转化为String类型
2.1.3.2 Implement ConcreteVerticesGraph

ConcreteVerticesGraph是基于点集的Graph实现。

首先实现Vertex类。Vertex类的实现如下:

rep:

private final String name;     						顶点的名称

private Map<String, Integer> sources = new HashMap<L, Integer>(); 	所有以该顶点为终点构成的边的起点和权值形成的Map

private Map<String, Integer> targets = new HashMap<L, Integer>();	所有以该顶点为起点构成的边的终点和权值形成的Map



method:

public Vertex(L name)                     	建立Vertex的Constructor

public Map<L, Integer> getSources()       	返回该Vertex的source Map

public Map<L, Integer> getTargets()       	返回该Vertex的target Map

public L getName()                        	返回该Vertex的名称

public void setSources(Map<L, Integer> sources)	将sources设置为该Vertex的sources

public void setTargets(Map<L, Integer> targets)	将targets设置为该Vertex的targets

public String toString()                  	将该Vertex的信息转为String

有了Vertex类就可以进一步实现ConcreteVerticesGraph了。

ConcreteVerticesGraph类的实现如下:

rep:

private final List<Vertex> vertices = new ArrayList<>();	Garph的点集


method:

public boolean add(String vertex);				向点集中加入新的点。

public int set(String source, String target, int weight);	遍历边集,如果存在一条从source到target的边,则将权值设为weight,
								返回旧的权值,如果要将权值设为0则删除这条边,如果不存在从source到
								target的边,则新建这样一条边并返回0.

public boolean remove(String vertex)				移除vertex顶点,并删去与其关联的所有边。点集中确实有vertex点并移除
								成功返回true,否则返回false。

public Set<String> vertices();					返回点集。

public Map<String, Integer> sources(String target);		返回将target点作为终点的所有边,将起点和权值加入到Map中返回。

public Map<String, Integer> targets(String source);		返回将source点作为起点的所有边,将终点和权值加入到Map中返回。

public String toString();					将图的信息转化为String类型
2.1.4 Problem 3: Implement generic Graph< L >
2.1.4.1 Make the implementations generic

将之前的两个实现ConcreteEdgesGraph和ConcreteVerticesGraph中的String都换成泛型即可,Edge和Vertex也应该改成泛型,具体修改见代码。

2.1.4.2 Implement Graph.empty()

将此前的实现中的String换成L,如下:

public static <String> Graph<String> empty() {

 	return new ConcreteEdgesGraph<String>();
 	
}
2.1.5 Problem 4: Poetic walks

这一个问题就是对我们之前实现的Graph类的验证。

2.1.5.1 Test GraphPoet

先编写GraphPoet的测试类。

这里用的语料和例子是main中的例子。

使用

This is a test of the Mugar.
Omni Theater sound system.

作为语料来形成语料库。

Test the system.

作为输入。

期待其输出应该为

Test of the system.。

测试代码如下:

@Test
public void testGraphPoet() throws IOException {
	final GraphPoet nimoy = new GraphPoet(new File("test/P1/Poet/mugar-omni-theater.txt"));
	final String input = "Test the system.";
  	assertEquals("Test of the system.", nimoy.poem(input));
}
2.1.5.2 Implement GraphPoet

首先应该有一个Graph来存储我们处理后的语料库。

具体的语料处理过程如下(实现于GraphPoet的构造方法中):

  1. 将语料库中的句子用空格分开,形成一个一个分开的单词同时将其中的字母都转化为小写,便于下一步的比较。
  2. 把每个单词作为顶点加入到图的顶点集中(由于图中要求没有重复顶点,因此重复的单词只会出现一次)。
  3. 之后将每个单词和它在句中的前一个单词之间加一条边:前一个单词à当前单词,如果之前没有这样的边相连则将权值设为1,此后如果再次遇到这样的边权值就在此前的基础上加1
  4. 遍历过全部的单词,语料库就建立完成了。

之后的过程是结合语料库对输入句子进行扩展(实现于public String poem(String input)方法中):

  1. 将输入的句子根据空格进行拆分成一个一个的单词。
  2. 对输入句子中的相邻的每一对单词,遍历语料库,寻找是否有单词恰好作为前一个单词的目标顶点和后一个单词的起始顶点,如果有则将其及其与前一个顶点的权值记录下来备用,最终遍历完语料库后将权值最大的这个点加入到原句的两个单词中间,如果遍历完成后仍然没有这样的单词则不插入任何单词。
  3. 遍历完整个输入句子整个拓展过程就完成了。
2.1.5.3 Graph poetry slam

更新main中的语料库以及输入句子,我在这里将语料库的句子改成了两个句子:

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

将输入句子改成了:

Seek to explore new and exciting synergies!

最终的运行结果为:
在这里插入图片描述

2.1.6 Before you’re done

请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。

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

使用了eclipse提供的提交方式如下图:

在这里插入图片描述

在这里给出你的项目的目录结构树状示意图。

项目的目录结构:

项目名称:Lab2-(学号)
            src
                P1
                   graph
                       ConcreteEdgesGraph.java
                       ConcreteVerticesGraph.java
                       Graph.java
                   poet
                       GraphPoet.java
                       Main.java
                       mugar-omni-theater.txt
            test
                P1
                   graph
                       ConcreteEdgesGraphTest.java
                       ConcreteVerticesGraphTest.java
                       GraphInstanceTest.java
                       GraphStaticTest.java
                   poet
                       GraphPoetTest.java
                       mugar-omni-theater.txt

2.2 Re-implement the Social Network in Lab1

该任务就是用第一个任务完成的Graph来重新实现实验一中P3的FriendshipGraph。用Graph中的方法来实现FriendshipGraph中的addVertex()、addEdge()和getDistance()三个方法。

2.2.1 FriendshipGraph类

利用Graph中提供的方法来重新实现FriendshipGraph中的方法,具体实现的思路在下面进行详述。

首先实例化一个Graph的people,以Person的对象作为朋友网络的节点。

下面实现FriendshipGraph中的三个关键方法。

public Set<Person> addVertex(Person person)
	调用Graph中的add(L Vertex)为朋友关系网络中添加成员,在添加前需要判断是否有重复的人,如果有则退出整个程序。添加返回经过防御性拷
	贝的成员列表。

public Set<Person> addEdge(Person p1, Person p2)
	添加p1到p2的边的关系,由于没有权值要求,则将边的权值统一设置为1来表示有从p1到p2的朋友关系(p1把p2当作朋友,单方面关系)。使用的
	是Graph中的set(Person source, Person target, int weight)来添加边。添加后返回经过防御性拷贝的p1的朋友列表。

public int getDistance(Person p1, Person p2)
	寻找两个点之间的距离,使用的依旧是实验一中用到的广度优先搜索,利用队列这一数据结构,从p1出发,直到找到p2为止,这时找到p2必然是最
	短的距离。
2.2.2 Person类

使用此前实验一中P3中的Person类即可,但是由于图的结构直接调用Graph中,所以去我取消了之前放在Person中的朋友列表friendList这一rep,只剩下了String类的name用来存储该person的名字。

方法只有用来向新实例化的Person对象传入name的构造方法和得到Person的名字的getName()方法。

2.2.3 客户端main()

与实验一的P3中的main()相同。运行结果也相同,这里不再赘述。

2.2.4 测试用例

与实验一的P3中的测试用例相同。测试结果也相同,这里不再赘述。

2.2.5 提交至Git仓库

在这里给出你的项目的目录结构树状示意图。

项目名称:Lab2-1180300208
            src
                P2
                   FriendshipGraph.java
                   Person.java
            test
                P2
                   FriendshipGraphTest.java

2.3 Playing Chess

2.3.1 ADT设计/实现方案

设计了哪些ADT(接口、类),各自的rep和实现,各自的mutability/ immutability说明、AF、RI、safety from rep exposure。

1、Position
是否可变: mutability

AF: 坐标为(x, y)的位置

RI: 对x和y没有要求

Safety from rep exposure:  返回时使用了防御性拷贝

rep: 
    private int x;     横坐标
    
    private int y;     纵坐标

method: 
    public Position(int x, int y)          	创建一个横坐标为x纵坐标为y的位置
    
    public boolean setPosition(int x, int y)  	将横纵坐标设为(x, y)
    
    public int getX()                      	返回该位置的横坐标
    
    public int getY()                      	返回该位置的纵坐标
    
    public Position getPosition()        	返回该位置的拷贝
    
    public boolean equals(Object that)    	判断该位置与that位置是否相同
2、Piece
是否可变: mutability

AF: owner的一个类型为type的棋子,位置为pos,如果在棋盘上则状态为true,不在棋盘上状态为false

RI: 对owner, type, pos, state没有特别要求

Safety from rep exposure: 使用了final关键字

rep: 
	private final String owner;    该piece的所有者的名称

	private final String type;     该piece的类型

	private Position pos;          该piece的位置

	private boolean state;         该piece的状态(是否在棋盘上)

method: 
	public Piece(String owner, String type, boolean state) 新建一个所有者名称为owner类型为type状态为state的棋子

	public String getOwner()       返回该piece的所有者名称

	public String getType()        返回该棋子的类型

	public Position getPos()       返回该棋子的位置

	public boolean isOnBoard()     判断该棋子是否在棋盘上

	public boolean setPos(int x, int y)   重新修改棋子的位置到(x, y)

	public void setState(boolean state)   改变棋子的状态
3、Player
是否可变: mutability

AF: 一个名字为name的玩家,其棋子集合为pieceSet,走棋历史为history

RI: 名字name不能为空

Safety from rep exposure: 使用了final关键字

rep:
    	private final String name;     					该玩家的名字
   
    	private final Set<Piece> pieceSet = new HashSet<>();		该玩家拥有的棋子集合
    
    	private final List<String> history = new ArrayList<>(); 		该玩家的走棋历史

method: 
    	public Player(String name)     					新建一个名字为name的player
    
    	public boolean addPiece(Piece piece)				向player添加棋子,若已有该棋子或者该棋子的owner与该player的
    									name不同则返回false,如果没有则将其加到棋子集合中并返回true
    
    	public int pieceNumber()       					返回该player当前在棋盘上的棋子数目
    
    	public void addHistory(String history)				将history加到该player的走棋历史中
    
    	public String getName()        					返回该player的名字
    
    	public Set<Piece> getPieceSet()   					返回该player的棋子集合
    
    	public List<String> getHistory()  					获得该player的走棋历史
4、Board
是否可变: mutability

AF: 一个n*n的棋盘,棋子放在格中或者格点处

RI: 如果是格点处放置棋子,应该有(n+1)*(n+1)个放置位置;如果是格中放置棋子,应该有n*n个放置位置

Safety from rep exposure:  使用了final标签不直接返回board而是直接打印,所以RI一旦确定讲不会被改变,无需对representation进行检查

rep:
	private final boolean isCrossPlace;   		该棋盘上的棋子是否落在格点上

	private final int size;            		该棋盘的大小(方形棋盘每行的方格数)

	private final int actualSize;     		该棋盘的实际大小(一行可容纳的棋子数)

	private Piece[][] pieces;          		棋盘存放棋子的二维数组

	private boolean[][] hasPiece;     		判断棋盘某一位置是否有棋子

method:
	public Board(int size, boolean isCrossPlace)	建一个大小、棋子放置是否在格点已知的棋盘

    	public Piece getPiece(int x, int y)       	获得在(x, y)位置的棋子

    	public boolean xyHasPiece(int x, int y)   	判断(x, y)处是否有棋子

    	public void setPiece(Piece piece, int x, int y)	将piece棋子放置在棋盘的(x, y)处

    	public void removePiece(int x, int y)     	移除在(x, y)处的棋子

    	public void changePosition(int x1, int y1, int x2, int y2)            
    							将(x1, y1)处的棋子移到(x2, y2)处

    	public int getActualSize()                	获得每一行可容纳的棋子数

    	public int getSize()                      	获得每一行的方格数

    	public boolean getType()       			获得棋子放置在棋盘的位置是格点还是格中

    	public void printBoard()       			将棋盘打印到命令行
5、Action (interface)
public static Action empyt(String game) 	工厂方法,用来实例化指定的类(chess或go)
(1)ChessAction
是否可变: immutability

AF: chess游戏,由两位玩家和一个棋盘构成

RI: 两位玩家不能相同,名字也不能为空

Safety from rep exposure: 不将玩家和棋盘信息暴露出去

rep:
	private Player player1;        玩家一

	private Player player2;        玩家二

	private Board board;           国际象棋棋盘

method: 
	public void createPlayer1(String player1)     创建玩家一

	public void createPlayer2(String player2)     创建玩家二

	public void createBoard()                     创建国际象棋棋盘

	public boolean placePiece(Player player, Piece piece, int x, int y)	国际象棋没有这个操作,提示后直接返回false

	public boolean removePiece(Player player, int x, int y)			国际象棋没有这个操作,提示后直接返回false

	public boolean movePiece(Player player,int x1,int y1,int x2,int y2)	玩家player的操作:将己方位于(x1, y1)的棋子移动到
										(x2, y2)的位置
      		要注意的情况:	给的两个坐标是否在棋盘范围内
                   		起始位置和终点是否有棋子
                   		起点位置处的棋子是否为己方棋子

    	public boolean eatPiece(Player player,int x1,int y1,int x2, int y2)	玩家player的操作:用己方位于(x1, y1)的棋子吃
    										掉对方位于到(x2, y2)的棋子
		要注意的情况:	给的两个坐标是否在棋盘范围内
            			起始位置和终点是否有棋子
            			起点位置处的棋子是否为己方棋子
            			终点位置处的棋子是否为对方棋子

	public void printBoard()                      				打印此时棋盘

	public Player getPlayer1()                    				获得玩家一

	public Player getPlayer2()                    				获得玩家二

	public Piece getPieceAtXY(int x, int y)       				得到(x, y)处的棋子

	public void printHistory(Player player)       				打印player的走棋历史
(2)GoAction
是否可变: immutability

AF: go游戏,由两位玩家和一个棋盘构成

RI: 两位玩家不能相同,名字也不能为空

Safety from rep exposure: 不将玩家和棋盘信息暴露出去

rep:
	private Player player1;        玩家一

	private Player player2;        玩家二

	private Board board;           围棋棋盘

method: 
	public void createPlayer1(String player1)     创建玩家一

	public void createPlayer2(String player2)     创建玩家二

	public void createBoard()                     创建围棋棋盘

	public boolean placePiece(Player player, Piece piece, int x, int y)	玩家player的操作:将己方的piece棋子放置到(x, y)的位置
      		要注意的情况:	给的坐标是否在棋盘范围内
                   		piece是否是己方的棋子
                   		(x,y)处是否已经有棋子
                   		piece是否是已经在棋盘上的棋子

	public boolean removePiece(Player player, int x, int y)			玩家player的操作:将对方的位置在(x, y) 的棋子放置移除
      		要注意的情况:	给的坐标是否在棋盘范围内
                   		piece是否是对方的棋子
                  	 	(x, y)处是否有棋子

	public boolean movePiece(Player player,int x1,int y1,int x2,int y2)	围棋没有这个操作,提示后直接返回false

	public boolean eatPiece(Player player,int x1,int y1,int x2, int y2)	围棋没有这个操作,提示后直接返回false

	public void printBoard()                      打印此时棋盘

	public Player getPlayer1()                    获得玩家一

	public Player getPlayer2()                    获得玩家二

	public Piece getPieceAtXY(int x, int y)       得到(x, y)处的棋子

	public void printHistory(Player player)       打印player的走棋历史
6、Game
是否可变: immutability

AF: 作为ChessAction和GoAction的包装供MyChessAndGoGame调用

RI: 一经创建就不会被修改

Safety from rep exposure: 使用final关键字

rep: private final Action action;     客户端程序要用到的操作

method: 除构造方法外,其他方法均为ChessAction和GoAction的包装,不再详述

    	public Game(String game, String player1, String player2)		用根据游戏名创建一个新的游戏,并传入两个玩家的名称

    	public Player getPlayer1()

    	public Player getPlayer2()

    	public Piece getPiece(int x, int y)

    	public boolean placePiece(Player player, Piece piece, int x, int y)

    	public boolean removePiece(Player player, int x, int y) {

    	public boolean movePiece(Player player,int x1,int y1,int x2,int y2)

    	public boolean eatPiece(Player player,int x1,int y1,int x2, int y2)

    	public void printBoard()

    	public void printHistory(Player player)
2.3.2 主程序MyChessAndGoGame设计/实现方案

首先main方法读入游戏的名称(Chess或者Go)和两名玩家的名称,用这三个参数来建立一个新的游戏。为使代码整洁,将Chess和Go的操作放在不同的方法中,根据不同游戏类型进行调用。初始化游戏过程如下图所示:

在这里插入图片描述

对输入棋类和玩家的处理如下:

while (true) {            
        System.out.println("请输入要选择的棋类(Chess or Go):");            
        gameType = in.nextLine();            
        if (gameType.toLowerCase().equals("chess") || gameType.toLowerCase().equals("go") {                
        	break;            
        } else {                
        	System.out.println("输入不合法,请重新选择! ");            
        }
}

while(true) {            
        System.out.println("请输入玩家1的名字:");            
        player1 = in.nextLine();            
        System.out.println("请输入玩家2的名字:");            
        player2 = in.nextLine();            
        if(player1.equals("")) {                
        	System.out.println("玩家一名字为空,重新输入!");            
        } else if(player2.equals("")) {                
        	System.out.println("玩家二名字为空,重新输入!");            
        } else if(player1.equals(player2)) {                
        	System.out.println("两玩家名字相同,请重新输入!");            
        } else {                
        	break;
        }        
}

随后根据要实现的游戏类别以及玩家名称建立新的游戏,同时调用该游戏的操作方法,处理如下:

Game newGame = new Game(gameType, player1, player2);
                
System.out.println();        
if (gameType.toLowerCase().equals("chess")) {            
	game.Chess(newGame);        
} else if (gameType.toLowerCase().equals("go")) {            
	game.Go(newGame);        
}        

下面对Chess(Game game)和Go(Game game)两个方法进行解析。

除了命令不同和调用的操作方法不同外,两个方法对输入命令的解析和处理方式是一样的,都是在每一轮选择不同的玩家作为命令的发出者,将该玩家输入的命令通过空格拆分开,通过第一个单词来判断调用的方法,用剩下的作为参数来实现具体的棋子操作。对于两种游戏来说处理的方式是完全一样的,处理的代码如下图所示:

if(turn) {                
	player = game.getPlayer1();                
	turn = !turn;            
} else {                
	player = game.getPlayer2();                
	turn = !turn;            
}            
System.out.println("操作提示:\n"                    
		+ "落子:set 要落子位置横坐标 要落子位置纵坐标(以上各项用空格隔开)\n"                    
		+  "提子:remove 要提子位置横坐标 要提子位置纵坐标(以上各项用空格隔开)\n"                    
		+  "结束游戏:end");            
System.out.print("\n轮到" + player.getName() + "进行操作:");                        

commandLine = in.nextLine();            
splitcmd = commandLine.split(" ");

下面对两种游戏的操作分别进行说明:

Chess的移子操作:
命令行输入格式为: move x1 y1 x2 y2

其意义为: 当前玩家将自己的在(x1, y1)处的棋子移到(x2, y2)处

操作实例如下:

在这里插入图片描述
在这里插入图片描述

Chess的吃子操作:
命令行输入格式为: eat x1 y1 x2 y2

其意义为: 当前玩家用自己在(x1, y1)处的棋子替换掉对方在(x2, y2)处的棋子

操作实例如下:

在这里插入图片描述

Go的落子操作:
   命令行输入格式为: set x y

其意义为: 将当前玩家尚未在棋盘上的棋子放置在(x, y)处

操作实例如下: (只截取了部分棋盘进行展示)

在这里插入图片描述

Go的提子操作:
   命令行输入格式为: remove x y

其意义为: 将对方玩家在棋盘上位置为(x, y)的棋子拿下棋盘

操作实例如下:

提子前:

在这里插入图片描述

提子后:

在这里插入图片描述

双方任意一方输入end后游戏将被退出,如下图所示,会给出最后棋盘的样子。

在这里插入图片描述

之后会提示是否查询走棋历史,输入”yes”或者”y”将给出双方成功进行的走棋历史(即如果有步骤走棋失败将不会记录在走棋历史中),实例如下:

在这里插入图片描述

2.3.3 ADT和主程序的测试方案

介绍针对各ADT的各方法的测试方案和testing strategy。

1、PositionAction
Test strategy: 按照逻辑对其进行测试即可,对x, y没有特别要求。
2、PieceTest
Test strategy:  由于对owner, owner, type, pos, state没有特别要求,因此简单测试逻辑即可
3、PlayerTest
Testing strategy:  在添加棋子时要注意该棋子是否重复添加
		   该棋子是否属于该player
4、BoardTest
Testing strategy:  应该考虑不同状态的两种棋盘: 棋子落在方格中以及棋子落在格点处。而对棋盘上的棋子进行操作时应该考虑到位置是否在棋盘的范围
		   之外,以及要操作的位置是否有棋子由更高级的操作进行判断,这里不做非法测试。
5、ChessActionTest
Testing strategy:  各项操作应当符合实验手册中给定的规则,每一项的设计思路会展示在每一个方法的测试之前。
6、GoActionTest
Testing strategy:  各项操作应当符合实验手册中给定的规则,每一项的设计思路会展示在每一个方法的测试之前。
7、GameTest
由于game只是ChessAction和GoAction的操作的包装,所有的操作只是调用ChessAction和GoAction的方法,因此无需进行重复测试。

项目目录结构:

 项目名称:Lab2-1180300208
            src
                P3
                   Action.java
                   Board.java
                   ChessAction.java
                   Game.java
                   GoAction.java
                   MyChessAndGoGame.java
                   Piece.java
                   Player.java
                   Position.java
            test
                P3
                   BoardTest.java
                   ChessActionTest.java
                   GameTest.java
                   GoActionTest.java
                   PieceTest.java
                   PlayerTest.java
                   PositionTest.java
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值