哈工大2020春软件构造Lab2实验报告

实验报告只是为了提供给学弟学妹们参考,所以很多代码都没有完整给出,希望学弟学妹们只用来参考,请勿直接抄袭!!!
有问题请联系QQ:1187987704

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 实验环境配置

简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。
特别是要记录配置过程中遇到的问题和困难,以及如何解决的。
Eclipse IDE,由于第一次实验已经配置好了,所以没有困难

在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
https://github.com/ComputerScienceHIT/Lab2-1180300120.git

3 实验过程

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

3.1 Poetic Walks

此任务主要是自己根据已给出的框架设计一个有关图的ADT,然后能够实现规定的功能,并且实际应用这个ADT

3.1.1 Get the code and prepare Git repository

从实验说明书中的github地址中点击clone即可下载到本地

3.1.2 Problem 1: Test Graph

测试静态方法生成String类型的Graph
在这里插入图片描述

3.1.3 Problem 2: Implement Graph

以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。

3.1.3.1 Implement ConcreteEdgesGraph

首先实现其中的Edge类,里面的fields为两个private的起点和终点,一个private的权值,构建函数的参数列表为(String Source, String Target, int Weight),表示不变量为起点终点不为空,边的权值大于0,这样就可以写出Edge的checkRep,观察器一共有3个,直接返回对应的变量即可,变值器这里只可以改变权值,因为改变终点起点在本次实现中的意义不大,所以变值器值限于改变权值,toString我设置的格式是“source->target-weight”,要注意Edge所有的方法里面每次返回前都要checkRep。
然后就是对ConcreteEdgesGraph里面的对应于Graph的方法进行实现了。
constructor: 没有其他的特殊要求,构建函数为空即可

checkRep: vertices里面的元素都不能为空,edges里面的要求和Edge的一样

add: 首先判断vertices里面是否已经包含了要加入的点,如果是则返回false,否则,将要加入的点加入到vertices里面。

set: 首先进行判断传入的source和target是否已经在vertices里面,如果不在那么需要将其加入到vertices里,再进行判断source->target这条边是否在edges里面,如果在,则将这条边的权值改为新的权值,并返回旧的权值,如果新的权值为0,则移除这条边,如果此边之前不存在,则将一个新的边加入到edges里面,并返回0

remove: 如果此点不在vertices里面则直接返回false,否则,将其从vertices里面移除,然后遍历所有的edges里面的Edge,将所有起点或终点是此点的边也一起移除,并返回true

vertices: 这个就直接返回vertices即可

sources: 新建一个map,遍历所有的edges,将终点与传入的终点相同的<source,weight>加入到新建的map中,最后返回新建的map即可

targets: 新建一个map,遍历所有的edges,将起点与传入的起点相同的<target,weight>加入到新建的map中,最后返回新建的map即可

toString: 我设计的格式是先把所有的点打印一遍,然后对于每条边都调用Edge的toString打印一遍即可

对于测试策略,返回值的正确性通过GraphInstanceTest来检测,其中add,set,remove需要对内部的正确性进行检测,首先我们对toString进行验证,一旦toString的正确性可以保证,那么我们就可以通过toString的结果来检测add,set,remove的正确性,这些就比较好实现了,具体代码这里就不阐述了,主要要注意的是尽可能增大检测的代码覆盖度。
在这里插入图片描述在这里插入图片描述

3.1.3.2 Implement ConcreteVerticesGraph

首先是对Vertex的设计,里面的fields有两个,一个是private的起点,另个一是private的Map,里面存的是与此起点之间有边的终点和权值,构建函数的参数只有起点,对于checkRep需要检测起点不为空,所有终点不为空,权值大于0,有两个观察器,分别获得起点和<终点,权值>的map,toString的设计类似Edge,也是source->target->weight
然后在ConcreteVerticesGraph里面实现Graph里要求的方法
constructor: 没有特殊要求,构建函数为空即可

checkRep: 对于所有Vertices中的点都直接调用Vertex中的checkRep即可

add: 如果vertices中所有的点的起点都不是待加入的点,则建立一个起点为此点的vertex,然后加入到vertices里面,并返回true,如果里面有一个起点是此点的vertex则返回false

set: 首先判断起点是否在vertices中,如果没有则建立新的vertex起点,如果有,则遍历起点的map,查找里面是否有终点,如果有则记录之前的权值,新的权值如果不为0,则改变权值,如果为0,则删除这个键值对,并返回之前的权值,如果没有终点,则在起点里面的map中新加入一个<终点,权值>,并返回0

remove: 首先在vertices里面找有没有vertex,如果有直接移除,并查找所有的vertices中的点的Map,如果有以vertex为终点的也一起删除,并返回true,如果没找到,则返回false

vertices: 遍历vertices中的所有点,将source加入set,最后返回这个set即可

sources: 遍历所有的vertices中的点的map,如果key等于target,则将这个点的source和对应的weight加入到新的Map<String, Integer>中,最后返回这个Map即可

targets: 遍历所有的vertices中的点,如果source等于传入的source,则返回此点的map即可

toString: 与ConcreteEdgesGraph的toString格式一样

对于ConcreteVerticesGraph的测试,返回值的正确性通过GraphInstanceTest检测,add,set,remove需要对内部的正确性进行检测,首先我们对toString进行验证,一旦toString的正确性可以保证,那么我们就可以通过toString的结果来检测add,set,remove的正确性,这些就比较好实现了,具体代码这里就不阐述了,主要要注意的是尽可能增大检测的代码覆盖度。
在这里插入图片描述在这里插入图片描述

3.1.4 Problem 3: Implement generic Graph

3.1.4.1 Make the implementations generic

将所有的对应的String改成L即可

3.1.4.2 Implement Graph.empty()

这个直接返回一个新的空的实例即可,return new ConcreteEdgesGraph();

3.1.5 Problem 4: Poetic walks

3.1.5.1 Test GraphPoet

先对已经给出的示例进行检测
然后对有多个bridge词的进行检测,要能准确找到权值大的边
由于我的操作中有去除最后一个符号字符的步骤,所以要注意的是,所有句子后都要有一个标点符号,否则可能会出现错误

3.1.5.2 Implement GraphPoet

GraphPoet:首先读入给出的句子,然后将词划分,然后每两个词之间都用set加入边,要考虑已经包含这条边的情况,那就需要先查询到这条边的权值后,将权值加一,在利用set,这里具体的实现方法就是如果graph.vertices()中如果同时包含起点终点,那么就要取其权值加一再用set,如果至少有一个不在vertices里面,则直接set就行,权值设为1,checkRep的检测和Graph中的一样,就是点不为空,权值大于0

Poem:这个实现起来麻烦些,但是思路还是挺清晰的,首先我们还是将句子分成词(注意去掉最后的标点符号),相邻两词间要在graph中找是否有一个有且仅有两条边构成的路径,如果有就将这两条边中间的那个词也加入到句子中,如果有多个这样的路径,则选两条边权值和最大的那个。首先假设我们输入的句子中相邻两词为A,B,取A的targets和B的sources,取交集,设交集为{C,D,E},则计算AC+CB,AD+DB,AE+EB,假设AC+CB最大,则AB之间就加入一个C,这样就行了。toString直接调用Graph的toString即可。

3.1.5.3 Graph poetry slam

这是我已给出的句子,下面根据这个测试
在这里插入图片描述

一个简单的测试:
在这里插入图片描述

有多条路径的测试:
在这里插入图片描述

3.1.6 Before you’re done

请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
git add .
git commit -m “Lab2-1180300120”
git push
在这里给出你的项目的目录结构树状示意图。

在这里插入图片描述

3.2 Re-implement the Social Network in Lab1

利用P1中的ADT完成Lab1中的Social Network

3.2.1FriendshipGraph类

利用Graph创建一个新的ConcreteEdgesGraph
addVertex: 检测重名异常后,直接利用graph.add()加入即可

addEdge: 检测两个人为同一个人的异常后,直接调用两次graph.set(),因为是无向图所以要调用两次,并且权值都为1

getDistance: 这个就与Lab1的思路一样了,同样是利用广度优先搜索,但是其中一些可以利用Graph中的功能。首先建一个队列,一个访问标记的Map<Perosn, Boolean>,一个距离的Map<Perosn, Integer>,如果src和dst相同,则返回0,否则,src入队列,设为已访问,并距离设为0,然后将队列头出队列,graph.target(src).keySet()中的未访问的点入队列,距离设为队列头的距离加一,设为已访问,依次类推,进行下去,直到找到dst返回dst的距离,如果队列空了还没找到dst,则返回-1

3.2.2 Person类

Person类主要就是存名字,实现起来很简单,这里给出代码,不做解释。

public class Person {
	private String Name;

    public Person(String PersonName) {
        this.Name = PersonName;
    }
    
    public String getName() {
    	return this.Name;
    }
}

3.2.3 客户端main()

客户端main就是Lab1中的用例:

FriendshipGraph graph = new FriendshipGraph();
		 Person rachel = new Person("Rachel");
		 Person ross = new Person("Ross");
		 Person ben = new Person("Ben");
		 Person kramer = new Person("Kramer");
		 graph.addVertex(rachel);
		 graph.addVertex(ross);
		 graph.addVertex(ben);
		 graph.addVertex(kramer);
		 graph.addEdge(rachel, ross);
		 graph.addEdge(ross, rachel);
		 graph.addEdge(ross, ben);
		 graph.addEdge(ben, ross);
		 assertEquals(1, graph.getDistance(rachel, ross));
		 assertEquals(2, graph.getDistance(rachel, ben));
		 assertEquals(0, graph.getDistance(rachel, rachel));
		 assertEquals(-1, graph.getDistance(rachel, kramer));

3.2.4 测试用例

1.重名测试:加入重名的人,检测抛出异常

2.加边时,在同一个人之间加边(A->A),检测抛出异常

3.简单图测试:就是Lab1中题目给出的测试

4.复杂图测试:关系图如下:

在这里插入图片描述

以下为测试结果:
在这里插入图片描述
在这里插入图片描述

3.2.5 提交至Git仓库

如何通过Git提交当前版本到GitHub上你的Lab3仓库。
git add .
git commit -m “Lab2-1180300120”
git push

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

在这里插入图片描述

3.3 Playing Chess

自己从零设计一个可以玩棋类游戏的ADT等。

3.3.1 ADT设计/实现方案

设计了哪些ADT(接口、类),各自的rep和实现,各自的mutability/ immutability说明、AF、RI、safety from rep exposure。
必要时请使用UML class diagram(请自学)描述你设计的各ADT间的关系。

3.3.1.1 Player(类)

Player主要是记录此玩家的名字,
String name是不可变的,因为没有变值器

在这里插入图片描述

3.3.1.2 Position(类)

Position主要是记录一个坐标,x和y都是可变的。
在这里插入图片描述

3.3.1.3 Piece(类)

Piece主要是记录一个棋子的有关信息,包括棋子的名字,棋子所属的玩家,棋子位于的坐标,是可变的,因为棋子的信息随时都有可能要自修改。
在这里插入图片描述

3.3.1.4 Board(类)

Board主要是创建一个相应大小的棋盘,是可变的,因为棋盘上的棋子是可变的。

在这里插入图片描述

3.3.1.5 Action(接口)

这个接口定义了游戏的方法,他的两个实例类是goClass和chessClass
所有的规约都在Action接口中已给出,这里不再重复说明

3.3.1.6 goClass(类)

是围棋的类,这里面包括了围棋操作
fields:

private Board b = new Board("go");
	private Piece[][] board = b.getBoard();		
//	public Piece[][] board = b.getBoard();		//测试时使用
	private final int goNum = 18;
	private Player P1;
	private Player P2;
	private int num1 = 0;
	private int num2 = 0;
//	public int num1 = 0;		//测试时使用
//	public int num2 = 0;		//测试时使用
	private String stepP1 = "";
	private String stepP2 = "";
//	public String stepP1 = "";		//测试时使用
//	public String stepP2 = "";		//测试时使用

constructor: 参数列表为(String P1, String P2)代表两个玩家的名字

checkRep: 验证两个玩家的名字不为空

boardInt(): 初始化一个棋盘,由于是围棋,所以空棋盘就行

printBoard(): 打印棋盘

calculate(): 计算两个玩家在棋盘上的棋子数

step(String player): 查看player的历史步骤,但是只能在游戏结束后查看

isHave(int x, int y): 查询(x,y)位置的占用情况

move(String player, int x, int y, int a, int b): 落子操作,其中player为操作玩家的名字,(x,y)为要落子的位置,a和b只是占位符的作用,可以使任意整数

eat(String player, int x, int y, int a, int b): 提子操作,其中player为操作玩家的名字,(x,y)为要提子的位置,a和b只是占位符的作用,可以使任意整数

3.3.1.7 chessClass(类)

是国际象棋的类,这里面包括了国际象棋操作
fields:

private Board b = new Board("chess");
	private Piece[][] board = b.getBoard();
//	public Piece[][] board = b.getBoard();	//测试时使用
	private final int chessNum = 8;
	private Player P1;
	private Player P2;
	private int num1 = 16;
	private int num2 = 16;
//	public int num1 = 16;		//测试时使用
//	public int num2 = 16;		//测试时使用
	private String stepP1 = "";
	private String stepP2 = "";
//	public String stepP1 = "";		//测试时使用
//	public String stepP2 = "";		//测试时使用

constructor: 参数列表为(String P1, String P2)代表两个玩家

checkRep: 两个玩家名字不为空即可

other(String Player): 获取另一玩家名字,这个在吃子时会用到

boardInt(): 初始化一个棋盘,由于是国际象棋,所以要把每方初始的16个棋子摆放好

printBoard(): 打印棋盘

calculate(): 计算两个玩家在棋盘上的棋子数

step(String player): 查看player的历史步骤,但是只能在游戏结束后查看

isHave(int x, int y): 查询(x,y)位置的占用情况

move(String player, int src_x, int src_y, int dst_x, int dst_y): player为操作的玩家,(src_x, src_y)为初始位置,(dst_x, dst_y)为目的位置,将自己的棋子从初始位置移动到目的位置

eat(String player, int src_x, int src_y, int dst_x, int dst_y): player为操作的玩家,(src_x, src_y)为初始位置,(dst_x, dst_y)为目的位置,将自己的初始位置棋子从初始位置移动到目的位置,并吃掉目的位置的对方的棋子。

3.3.1.8 Game(类)

为游戏创建初始信息,包括两个玩家名字player1, player2,和Action,是不可变的。
在这里插入图片描述

3.3.2 主程序MyChessAndGoGame设计/实现方案

辅之以执行过程的截图,介绍主程序的设计和实现方案,特别是如何将用户在命令行输入的指令映射到各ADT的具体方法的执行。
首先询问游戏类型,和两个玩家的名字,然后根据游戏类型创建一盘游戏,在根据是go还是chess给出操作信息表,
对于go:

"1.放置一颗棋子(玩家名字 x y)\n" 	//调用move
"2.提子(玩家名字 x y)\n"				//调动eat
"3.查询某个位置的占用情况(x y)\n"	//调用isHave
"4.计算两个玩家分别在棋盘上的总数\n"	//调用calculate
"5.获取帮助列表\n"

对于chess:

"1.移动棋盘上某个位置的棋子至新的位置(玩家名字 起始x 起始y 目的x 目的y)\n"
//调用move
	"2.吃子(玩家名字 起始x 起始y 目的x 目的y)\n"		//调用eat
	"3.查询某个位置的占用情况(x y)\n"					//调用isHave
	"4.计算两个玩家分别在棋盘上的总数\n"					//调用calculate	
"5.获取帮助列表\n"

然后一直重复玩家选择功能并输入相关信息的操作,直到一方输入了end,游戏结束并自动打印双方操作的历史记录。要注意的是只有一方进行了move或eat操作之后才会切换到下一玩家操作,其他查询操作不算入步骤。

3.3.3 ADT和主程序的测试方案

介绍针对各ADT的各方法的测试方案和testing strategy。
介绍你如何对该应用进行测试用例的设计,以及具体的测试过程。

对Player的测试:

public class PlayerTest {
	
	//测试策略
	/*
	 * 由于Player类比较简单,只是与玩家名字有关,所以,能够返回正确的名字即可
	 */
	@Test
	public void playerTest() {
		Player player = new Player("A");
		assertEquals("A", player.getName());
	}
}

对Position的测试:

public class PositionTest {
	
	//测试策略
	/*
	 * 对于Position类,主要需要对以下功能进行测试
	 * 首先将Position与一个(x,y)相关联
	 * 1.可以获取Position的X和Y
	 * 2.可以对Position进行修改
	 */
	@Test
	public void positionTest() {
		Position p = new Position(1, 2);
		assertEquals(1, p.getX());
		assertEquals(2, p.getY());
	}
	
	@Test
	public void positionChangeTest() {
		Position p = new Position(1, 2);
		p.change(3, 4);
		assertEquals(3, p.getX());
		assertEquals(4, p.getY());
	}
}

对Piece的测试:

public class PieceTest {
	
	//测试策略
	/*
	 * 对于Piece类需要测试以下功能
	 * 首先建立一个Piece,包括棋子名称,Player,Position
	 * 1.对棋子名称,玩家和Position进行检测,是否能得到正确的结果
	 * 2.对change进行检测,是否能有效的修改Piece
	 */
	@Test
	public void pieceTest() {
		Player player = new Player("Tom");
		Position pos = new Position(1, 2);
		Piece piece = new Piece("B", player, pos);
		assertEquals("B", piece.getName());
		assertEquals("Tom", piece.getPlayer().getName());
		assertEquals(1, piece.getPosition().getX());
		assertEquals(2, piece.getPosition().getY());
	}
	
	@Test
	public void pieceChangeTest() {
		Player player = new Player("Tom");
		Position pos = new Position(1, 2);
		Piece piece = new Piece("B", player, pos);
		piece.change("W", new Player("Jerry"), 3, 4);
		assertEquals("W", piece.getName());
		assertEquals("Jerry", piece.getPlayer().getName());
		assertEquals(3, piece.getPosition().getX());
		assertEquals(4, piece.getPosition().getY());
	}
}

对Game的测试:
对goClass的测试:(具体实现见代码)
再goClassTest.java中,我将全部代码注释掉了,如果要测试需要先将goClass中部分private改成public,然后解除goClassTest.java的注释再进行测试

public class GameTest {
	
	//测试策略
	/*
	 * 对于Game,其中主要存储整盘游戏的Board,Players
	 * 我们只需要测试能否得到正确的两个Player即可,
	 */
	
	@Test
	public void gameTest() {
		Game game1 = new Game("chess", "Tom", "Jerry");
		Game game2 = new Game("go", "Tom", "Jerry");
		assertEquals("Tom", game1.getPlayer1());
		assertEquals("Jerry", game1.getPlayer2());
		assertEquals("Tom", game2.getPlayer1());
		assertEquals("Jerry", game2.getPlayer2());
	}
}

对于chessClass的测试:(具体实现见代码)
再chessClassTest.java中,我将全部代码注释掉了,如果要测试需要先将chessClass中部分private改成public,然后解除chessClassTest.java的注释再进行测试

public class chessClassTest {
	//这里所有的测试都被注释掉了,在测试时没有问题,如果要运行需要将chessClass中的private改成public方可去掉下面测试的注释然后运行测试程序
	
		//测试策略(以下注释掉的测试如果需要使用的话,需要将chessClass中的标记的private改成public再测试)
		/*
		 * 作为一个核心的类,我们要对齐检测以下功能,但是要注意,在测试时需要把chessClass中的private暂时改成public
		 * 1.move,检测能否正确的完成移动棋子操作
		 * 2.eat,检测能否正确的完成吃子操作
		 * 3.isHave,检测能否准确访问一个位置的信息
		 * 4.calculate,检测能否准确计数
		 * 5.step,检测能否准确记录步骤
		 */
	
	/*
	 * 对于move,我们要暂时将chessClass中的Piece[][] board改成public,然后测试
	 */
	
	@Test
	public void moveTest() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		assertEquals(" · ", chess.board[2][0].getName());
		assertEquals("co", chess.board[2][0].getPlayer().getName());
		chess.move("Tom", 0, 0, 2, 0);
		assertEquals(" R1", chess.board[2][0].getName());
		assertEquals("Tom", chess.board[2][0].getPlayer().getName());
	}
	
	/*
	 * 以下是对move的异常测试
	 */
	
	@Test(expected = Exception.class)
	public void moveExceptionTest1() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("A", 0, 0, 2, 0);
	}
	
	@Test(expected = Exception.class)
	public void moveExceptionTest2() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 18, 18, 0, 0);
	}
	
	@Test(expected = Exception.class)
	public void moveExceptionTest3() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 0, 0, 18, 18);
	}
	
	@Test(expected = Exception.class)
	public void moveExceptionTest4() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 0, 0, 7, 0);
	}
	
	@Test(expected = Exception.class)
	public void moveExceptionTest5() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 2, 0, 3, 0);
	}
	
	@Test(expected = Exception.class)
	public void moveExceptionTest6() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 0, 0, 0, 0);
	}
	
	@Test(expected = Exception.class)
	public void moveExceptionTest7() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 7, 0, 2, 0);
	}
	
	/*
	 * 对于eat我们要暂时将chessclass中的Piece[][] board改成public,然后测试
	 */
	
	@Test
	public void eatTest() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		assertEquals(" K2", chess.board[7][4].getName());
		assertEquals("Jerry", chess.board[7][4].getPlayer().getName());
		chess.eat("Tom", 0, 0, 7, 4);
		assertEquals(" R1", chess.board[7][4].getName());
		assertEquals("Tom", chess.board[7][4].getPlayer().getName());
	}
	
	/*
	 * 以下是对eat的异常测试
	 */
	
	@Test(expected = Exception.class)
	public void eatExceptionTest1() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("A", 0, 0, 7, 0);
	}
	
	@Test(expected = Exception.class)
	public void eatExceptionTest2() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("Tom", 18, 18, 7, 0);
	}
	
	@Test(expected = Exception.class)
	public void eatExceptionTest3() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("Tom", 0, 0, 18, 18);
	}
	
	@Test(expected = Exception.class)
	public void eatExceptionTest4() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("Tom", 2, 0, 7, 0);
	}
	
	@Test(expected = Exception.class)
	public void eatExceptionTest5() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("Tom", 0, 0, 2, 0);
	}
	
	@Test(expected = Exception.class)
	public void eatExceptionTest6() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("Tom", 0, 0, 0, 0);
	}
	
	@Test(expected = Exception.class)
	public void eatExceptionTest7() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("Tom", 7, 0, 6, 0);
	}
	
	@Test(expected = Exception.class)
	public void eatExceptionTest8() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.eat("Tom", 0, 0, 1, 0);
	}
	
	/*
	 * 对于step,我们需要暂时将stepP1和stepP2改成public,再测试
	 */
	
	@Test
	public void stepTest() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 0, 0, 2, 0);
		chess.move("Jerry", 7, 0, 5, 0);
		chess.eat("Tom", 2, 0, 5, 0);
		chess.step("Tom");		//确保step能正常运行
		chess.step("Jerry");
		assertEquals("从(0,0)将 R1移动到(2,0)\n用(2,0)处的 R1吃掉了(5,0)处的 R2\n", chess.stepP1);
		assertEquals("从(7,0)将 R2移动到(5,0)\n", chess.stepP2);
	}
	
	/*
	 * 以下是对step的异常测试
	 */
	
	@Test(expected = Exception.class)
	public void stepExceptionTest() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.move("Tom", 0, 0, 2, 0);
		chess.move("Jerry", 7, 0, 5, 0);
		chess.eat("Tom", 2, 0, 5, 0);
		chess.step("A");
	}
	
	/*
	 * 对于calculate,我们主要是对num1和num2进行检测,所以需要暂时把num1和num2改成public
	 */
	
	@Test
	public void calculateTest() throws Exception{
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.calculate(); //为了确保calculate可以正常运行
		assertEquals(16, chess.num2);
		chess.eat("Tom", 0, 0, 7, 0);
		assertEquals(15, chess.num2);
	}
	
	/*
	 * 对于isHave,由于是直接打印信息的方法,无需用Test来检测,但是也已经确定功能正确
	 * 为了保证代码能正常运行,这里调用一次,同时可以更有效的观察代码覆盖度
	 */
	
	@Test
	public void isHaveTest() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.isHave(0, 0);
		chess.move("Tom", 0, 0, 2, 0);
		chess.move("Jerry", 7, 0, 5, 0);
		chess.isHave(2, 0);
		chess.isHave(5, 0);
	}
	
	/*
	 * 以下为对isHave的异常检测
	 */
	
	@Test(expected = Exception.class)
	public void isHaveExceptionTest() throws Exception {
		chessClass chess = new chessClass("Tom", "Jerry");
		chess.boardInt();
		chess.isHave(18, 18);
	}
}

测试截图:

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值