实验五 单元测试
一、实验目的
1)掌握单元测试的方法
2)学习XUnit测试原理及框架;
3)掌握使用测试框架进行单元测试的方法和过程。
二、实验内容
1、了解单元测试的原理与框架
2、结对编程的小组采用测试框架 对自己“结对编程”实验的程序模块(类)进行单元测试,提交单元测试报告
测试报告包括以下内容:
1)源码
2)测试用例设计 (结合单元测试的内容和模块功能设计测试用例)
3)选择的测试框架介绍、安装过程
4 )测试代码
5)测试结果与分析
3、push测试报告和测试代码到各自的github仓库
4、提交博客报告
实验内容
1.测试报告
1)源码(除去GUI设计和main源码)
细胞类,存放和细胞有关的数据和方法
package lifegame; public class Cell { private int Status; //0-死亡 1-存活 private int Living; //周围活细胞数目 Cell(){ Status=0; Living=0; } Cell(int m_Status,int m_Living){ Status=m_Status; Living=m_Living; } public int getStatus() { return Status;//获取状态 } public void setStatus(int m_Status) { Status=m_Status;//设置状态 } public int getLiving() { return Living;//获取当前周围活细胞数目 } public void setLiving(int m_Living) { Living=m_Living;//设置当前周围活细胞数目 } public void UpdateStatus() { if(this.getLiving()>3||this.getLiving()<2) this.setStatus(0); else if(this.getLiving()==3) this.setStatus(1); else this.setStatus(this.Status); } }
地图类,存放和地图有关的数据和方法
package lifegame; import java.util.Random; public class Map { final static public int x=16;//设置地图初始大小 final static public int y=16; public static Cell [][]initial() { Cell [][]cell=new Cell[x][y]; for(int i=0;i<x;i++) { for(int j=0;j<y;j++) { cell[i][j]=new Cell(); Random random=new Random(); cell[i][j].setStatus(random.nextInt(2)); //随机初始化设置细胞状态 } } return cell; } public static void getLiving(Cell [][]cell){ for(int i=0;i<x;i++) { for(int j=0;j<y;j++) { int living=0; if(i>0&&j>0) living+=cell[i-1][j-1].getStatus(); if(j>0) living+=cell[i][j-1].getStatus(); if(i<x-1&&j>0) living+=cell[i+1][j-1].getStatus(); if(i>0) living+=cell[i-1][j].getStatus(); if(i<x-1) living+=cell[i+1][j].getStatus(); if(i>0&&j<x-1) living+=cell[i-1][j+1].getStatus(); if(j<x-1) living+=cell[i][j+1].getStatus(); if(i<x-1&&j<x-1) living+=cell[i+1][j+1].getStatus(); cell[i][j].setLiving(living);//计算细胞周围八个格子的活细胞数目,特殊位置边界只计算地图内活细胞数目,地图外默认为死细胞 } } } public static int update(Cell [][]cell){ int count=0; for(int i=0;i<x;i++) { for(int j=0;j<y;j++) { int status=cell[i][j].getStatus(); cell[i][j].UpdateStatus(); if(status==cell[i][j].getStatus()) count++;//计算细胞达到演化平衡时的轮数 } } return count; } public static void printMap(Cell [][]cell) { for(int i=0;i<x;i++) { for(int j=0;j<y;j++) { System.out.print(cell[i][j].getStatus()+" ");//打印细胞地图 } System.out.println(); } } }
2)测试用例设计 (结合单元测试的内容和模块功能设计测试用例)
细胞类测试用例分析:以分析细胞为八格中心,周围有3个生细胞的就为生,不管原细胞死活;周围有2个生细胞,保持原细胞状态;其它情况,全部为死,不管原细胞死活。所以我们在设计测试用例时,只有当周围活细胞数目为2时,才需要考虑原细胞的状态。
①
输入当前周围活细胞数目 | 应获取的此细胞状态(0为死,1为活) |
1 | 0 |
3 | 1 |
4 | 0 |
②
输入当前周围活细胞数目 |
原细胞状态(0为死,1为活) |
应获取的此细胞状态(0为死,1为活) |
2 | 0 | 1 |
2 | 1 | 0 |
定义地图大小i=16,j=16地图类测试用例分析:一个细胞处于地图中的不同位置,以及地图中细胞的状态,对计算周围活细胞的数目都是有影响的。
输入设置所有细胞状态(0为死,1为活) | 应获取当前周围活细胞数目 |
0 | 0 |
1 |
i>0,j<15且j>0,j<15; 8 i=0或i=15时,j>0,j<15; 5 其它; 3 |
3)选择的测试框架介绍、安装过程
根据实验所用编程语言选择Eclipse自带的JUnit插件进行单元测试
首先将 JUnit4 单元测试包引入我们的项目:在该项目上点右键,点“属性”=>“java构建路径”=>“添加库”
然后选择JUnit,点击下一步,并完成
右键窗口,点击显示视图找到Java包的包资源管理器
在包资源管理器的控制台界面选择我们需要测试的类,右键点击该类弹出菜单,选择新建找到“JUnit 测试用例”
在弹出的对话框中,进行相应的选择
点击“下一步”后,系统会自动列出我们这个类中包含的方法,选择我们要进行测试的方法
然后系 统 会 自 动 生 成 一 个 新 类XXXXTest,里面包含一些空的测试用例。我们只需要将这些测试用例稍作修改即可使用
4 )测试代码
细胞测试类代码
package lifegame; import static org.junit.Assert.*; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class CellTest { private static Cell cell=new Cell(); @BeforeClass public static void setUpBeforeClass() throws Exception { ; } @AfterClass public static void tearDownAfterClass() throws Exception { ; } @Test public void testUpdateStatus() { cell.setLiving(1); cell.UpdateStatus(); assertEquals(0,cell.getStatus()); cell.setLiving(3); cell.UpdateStatus(); assertEquals(1,cell.getStatus()); cell.setLiving(4); cell.UpdateStatus(); assertEquals(0,cell.getStatus()); cell.setStatus(1); cell.setLiving(2); cell.UpdateStatus(); assertEquals(1,cell.getStatus()); cell.setStatus(0); cell.setLiving(2); cell.UpdateStatus(); assertEquals(0,cell.getStatus()); } }
地图测试类代码
package lifegame; import static org.junit.Assert.*; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class MapTest { private static Map map=new Map(); private static Cell [][]cell=new Cell[16][16]; @BeforeClass public static void setUpBeforeClass() throws Exception { cell=map.initial(); } @AfterClass public static void tearDownAfterClass() throws Exception { ; } @Test public void testGetLiving() { for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { cell[i][j].setStatus(1); } } map.getLiving(cell); for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { if(i>0&&i<15&&j>0&&j<15) assertEquals(8,cell[i][j].getLiving()); else if((i==0||i==15)&&(j>0&&j<15)||(j==0||j==15)&&(i>0&&i<15)) assertEquals(5,cell[i][j].getLiving()); else assertEquals(3,cell[i][j].getLiving()); } } for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { cell[i][j].setStatus(0); } } map.getLiving(cell); for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { assertEquals(0,cell[i][j].getLiving()); } } } }
5)测试结果与分析
细胞测试类结果
当我们将随意修改一个获取此细胞状态时,会发生报错
地图测试类结果
当我们随意修改一个获取当前周围活细胞值时,会发生报错
2.push测试代码到github仓库
实验小结
此次实验的代码实际上并不是我的结对编程代码,原因如下:1.关于c语言的MinUnit资源实在匮乏,后来我又找了xUnit系列的CUnit,配置n遍失败告终;2.又尝试用cppUnit,毕竟c++还是向下兼容c的,然后在vc++6.0下又配置失败,又决定改用vs,之前因为安装sql有冲突卸载过一次,然后一直安装失败!!!∑(゚Д゚ノ)ノ……于是我就换了一份代码(●—●),就是现在实验报告的这一份(对于结对代码我还在尝试,希望还是可以成功的),然后完成了对这份代码的单元测试。我认为成功的单元测试能证明这段代码的行为和我们期望的一致,保证程序的整体质量。。然后出现的问题都在单测中覆盖避免重复犯错,这样使我们每次修改都有信心。
思考题
比较以下二个工匠的做法,你认为哪种好?结合编码和单元测试,谈谈你的认识。
答:我认为工匠一的方法就像每写完一个函数或一个类就来进行单元测试,看看是否有bug,工匠二的方法就是将所有函数或类全部写完,最终一起来进行测试。那如果是实际上现实公司大项目场景下,应该是第二种,因为测试都是有专门的人员去测试的,当然是对整个项目的一同测试。而如果是个人的平时的不太紧张的项目代码测试,有可能的是第一种,因为这样更容易及早地发现错误并及时更正。所以我认为,方法多种,只要选择适合自己,适合项目的就可以。