Devops学习实践(六) Eclipse集成TestNg,mock编写单元测试
来源:互联网 发布:宝山区行知小学 编辑:程序博客网 时间:2024/06/08 13:06
单元测试也是开发中面临的一个重要工作,出了我们熟悉的junit,还可以采用testNg来实现这项工作。并且我们可以把它集成到Jenkins里面。本节开始介绍如何使用Jenkins与Ant、TestNg、mock进行单元测试并提高测试覆盖。首先第一部分是IDE环境(Eclipse)如何集成TestNg,并且与Mock一起完成测试代码编写
下面就就介绍一下整个过程。:
目标:
1、在eclipse中集成TestNg
2、编写测试类测试一般类
2、 通过powermock编写静态方法和调用静态类测试
一、集成TestNg
集成TestNg 分两部分,首先是我们开发工具里面集成TestNg,然后是在Jenkins中集成(下一节再说),在Jenkins中集成的目的是通过一些Jenkins的分析工具来分析项目的测试覆盖率等等。
1、Eclipse中集成TestNg
可以通过install 方式从http://beust.com/eclipse 从网站进行更新
2、因为要测试静态类和静态方法,所以需要引入powermock进行,需要注意的是powermock是基于mock基础上,分junit 和testng 两套框架的,所以下载的时候需要根据自己的工程进行区分。因为后期是为了在jenkins+testNg中使用,所以本次测试实践采用的是testNg路线。
Powermock 下载地址https://github.com/powermock/powermock/wiki/Downloads
进入后,下载基于testNg的 最新版本,如下图中的红色内容
注意 powermock有两套框架基于junit 和testNg,这两套是不同的不能混用。
二、准备测试工程
编写mock测试实践,主要通过demo进行日常常见的几个测试问题:
1、 普通类的测试
2、测试静态方法
3、测试静态类(如数据库连接类)
在构造的这个测试demo例子中, student 是实体类, StudentDao定义了一些student的操作接口, StudentDaoImpl 是操作接口的一个数据库的实现,在这个实现里面,会调用 DBOpt 进行数据库的操作。在DBOpt中,会调用 DBUtil 工具类(静态),进行数据库的连接。另外还写了StudentUtils 类(含静态方法),服务接口类StudentService
下面先给出待测试工程的结构
首先列出Student和StudentDao,StudentDaoImpl 三个类的代码
Student.java
package com.study.testngproj.entity;public class Student { int StuNumber; public int getStuNumber() {return StuNumber; } public void setStuNumber(int stuNumber) {StuNumber = stuNumber; } String Name; String BirthDay; String Sexual; String Grade; public String getName() {return Name; } public void setName(String name) {Name = name; } public String getBirthDay() {return BirthDay; } public void setBirthDay(String birthDay) {BirthDay = birthDay; } public String getSexual() {return Sexual; } public void setSexual(String sexual) {Sexual = sexual; } public String getGrade() {return Grade; } public void setGrade(String grade) {Grade = grade; } @Override public String toString() {return "Student [StuNumber=" + StuNumber + ", Name=" + Name+ ", BirthDay=" + BirthDay + ", Sexual=" + Sexual + ", Grade="+ Grade + ", getClass()=" + getClass() + ", hashCode()="+ hashCode() + ", toString()=" + super.toString() + "]"; }}StudentDao.java
package com.study.testngproj.entity.dao;import com.study.testngproj.entity.Student;public interface StudentDao { //add a new student boolean addStudent(Student stu) ; //del a student boolean delStudent(Student std); //query a student by student number Student queryStudent( int stuNumber );}
StudentDaoImpl.java
package com.study.testngproj.entity.dao.impl;import java.util.ArrayList;import java.util.List;import com.study.testngproj.dbutil.DBOpt;import com.study.testngproj.entity.Student;import com.study.testngproj.entity.dao.StudentDao;public class StudentDaoImpl implements StudentDao { DBOpt dbopt = new DBOpt(); @Override public boolean addStudent(Student stu) {// TODO Auto-generated method stubreturn false; } @Override public boolean delStudent(Student std) {// TODO Auto-generated method stubreturn false; } @Override public Student queryStudent(int stuNumber) {// TODO Auto-generated method stub// query stduent info from dbList myList = new ArrayList();myList = dbopt.queryStudentByNumFromDB(stuNumber);if(myList.size() != 1) { return null;}else { Student myStudent = new Student(); myStudent.setBirthDay( ((DBOpt)myList.get(0)).getStuBirthDay() ); myStudent.setName( ((DBOpt)myList.get(0)).getStuName() ); myStudent.setGrade( ((DBOpt)myList.get(0)).getStuGrade() ); myStudent.setSexual( ((DBOpt)myList.get(0)).getStuSexual() ); myStudent.setStuNumber( ((DBOpt)myList.get(0)).getStuNumber() ); return myStudent;} } }
接着,附上DB操作的两个类, DBOpt 和DBUtil
DBUtil.java 代码如下
package com.study.testngproj.dbutil;import java.io.IOException;import java.io.Reader;import java.io.Serializable;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import org.apache.log4j.Logger;import com.ibatis.common.resources.Resources;import com.ibatis.sqlmap.client.SqlMapClient;import com.ibatis.sqlmap.client.SqlMapClientBuilder;/** * <p> * Title: * * @author not attributable * @version 1.0 */public class DBUtil implements Serializable { private static final long serialVersionUID = 1L; public Integer getStuNumber() { return stuNumber; } public void setStuNumber(Integer stuNumber) { this.stuNumber = stuNumber; } public String getStuName() { return stuName; } public void setStuName(String stuName) { this.stuName = stuName; } public String getStuBirthDay() { return stuBirthDay; } public void setStuBirthDay(String stuBirthDay) { this.stuBirthDay = stuBirthDay; } public String getStuGrade() { return stuGrade; } public void setStuGrade(String stuGrade) { this.stuGrade = stuGrade; } public String getStuSexual() { return stuSexual; } public void setStuSexual(String stuSexual) { this.stuSexual = stuSexual; } private static Logger myLog = Logger.getLogger(DBUtil.class); String resource = "sqlmapconf.xml"; Reader reader; SqlMapClient sqlMap; // here define db object begin public Integer stuNumber; public String stuName; public String stuBirthDay; public String stuGrade; public String stuSexual; // here define db object end; int iCount = 0; private final static DBUtil singleton = new DBUtil(); /** * 返回这个类的静态实例的引用 * * @param // // * @return */ public static DBUtil getInstance() {return singleton; } /** default constructor */ public DBUtil() { //init(); } // 初始化,获取sqlMap,reader public synchronized boolean init() {myLog.info("DbOpt created!!");try { reader = Resources.getResourceAsReader(resource); sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader); myLog.info("DbOpt sqlmap Object Create Success->" + sqlMap.getDataSource().getConnection().getMetaData() .getURL() + ";UserName:" + sqlMap.getDataSource().getConnection().getMetaData() .getUserName());} catch (SQLException ee) { ee.printStackTrace(); myLog.error("DbOpt create error:" + ee.getMessage()); return false;} catch (IOException e) { e.printStackTrace(); myLog.error("DbOpt create error:" + e.getMessage()); return false;} finally { myLog.info("DbOpt init complete");}return true; } public List queryForList( String arg, Object obj) {List list = new ArrayList();try { this.sqlMap.startTransaction(); list = this.sqlMap.queryForList(arg, obj);}catch (SQLException e) { myLog.error("queryForList error" + e.toString());}finally { myLog.info("queryForList finally..."); try {this.sqlMap.endTransaction(); } catch (SQLException e) {e.printStackTrace();myLog.error("queryForList finally error" + e.toString()); }}return list; } public static void main(String[] args) { }}DBOpt.java 代码如下
package com.study.testngproj.dbutil;import java.util.ArrayList;import java.util.List;import org.apache.log4j.Logger;/** * <p> * Title: * * @author not attributable * @version 1.0 */public class DBOpt { // here define db object begin public Integer stuNumber; public String stuName; public String stuBirthDay; public String stuGrade; public String stuSexual; // end public Integer getStuNumber() {return stuNumber; } public void setStuNumber(Integer stuNumber) {this.stuNumber = stuNumber; } public String getStuName() {return stuName; } public void setStuName(String stuName) {this.stuName = stuName; } public String getStuBirthDay() {return stuBirthDay; } public void setStuBirthDay(String stuBirthDay) {this.stuBirthDay = stuBirthDay; } public String getStuGrade() {return stuGrade; } public void setStuGrade(String stuGrade) {this.stuGrade = stuGrade; } public String getStuSexual() {return stuSexual; } public void setStuSexual(String stuSexual) {this.stuSexual = stuSexual; } private static Logger myLog = Logger.getLogger(DBOpt.class); // 查询通过学生的ID号 public List queryStudentByNumFromDB(Integer stuNumber) {List retlist = new ArrayList();List mylist = new ArrayList();this.setStuNumber(stuNumber);myLog.info("queryStudentByNumFromDB,begin...");mylist = DBUtil.getInstance().queryForList("queryStudentByNumFromDB",this);myLog.info("queryStudentByNumFromDB, result list size is:"+ mylist.size() + ";");for (int i = 0; i < mylist.size(); i++) { String tmp ="Number=" + ((DBOpt) mylist.get(i)).getStuNumber() +";Name="+ ((DBOpt) mylist.get(i)).getStuName()+";Birthday="+ ((DBOpt) mylist.get(i)).getStuBirthDay()+";Grade="+ ((DBOpt) mylist.get(i)).getStuGrade()+";Sexual="+ ((DBOpt) mylist.get(i)).getStuSexual(); myLog.info("queryStudentByNumFromDB result:" + tmp); retlist.add(tmp);}myLog.info("queryStudentByNumFromDB, End....");return retlist; } public static void main(String[] args) { }}
最后附上StudentUtil 和 StudentService 代码
StudentUtil.java 代码如下:
package com.study.testngproj.entity;public class StudentUtils { public static int getStudent() {throw new UnsupportedOperationException(); } public static void createStudent( Student student) {throw new UnsupportedOperationException(); }}StudentService.java 代码如下:
package com.study.testngproj;import com.study.testngproj.entity.Student;import com.study.testngproj.entity.StudentUtils;public class StudentService { public void createStudent(Student student) {StudentUtils.createStudent(student); }}
三、下面编写测试代码
1、建立test目录,依据类的包结构,编写测试类
先将powermock解压后,整个目录拷贝到工程里面,通过右键加入到buildpath里面
2、建立测试目录,编写测试代码
最后的目录结构如下图:
一般建议在原类的包路径建立测试类,这样比较清晰,由于根目录区分开,所以也不容易混淆
3、在工程目录下,建一个testng.xml 文件,这个文件是为testng调用进行配置指引的
testng.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"><suite name="Suite"> <test name="Test"> <classes> <class name="com.study.testngproj.entity.student"/> <class name="com.study.testngproj.entity.dao.impl.StudentDaoImplTest"/> </classes> </test> <!-- Test --></suite> <!-- Suite -->
4、下面附上具体4个测试用例的代码
1)StudentServiceTest.java 测试静态方法
package com.study.testngproj;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PrepareForTest;import com.study.testngproj.entity.Student;import com.study.testngproj.entity.StudentUtils;import org.testng.annotations.Test;@PrepareForTest(StudentUtils.class)public class StudentServiceTest { @Test public void testCreateStudentWithMock() {PowerMockito.mockStatic( StudentUtils.class);Student stu = new Student();PowerMockito.doNothing().when(StudentUtils.class);final StudentService stuService = new StudentService();stuService.createStudent(stu); } }2)
StudentTest.java 的源码如下:
package com.study.testngproj.entity;import org.testng.Assert;import org.testng.annotations.Test;import com.study.testngproj.entity.Student;public class StudentTest { @Test public void studentCreate() {Student stuObj = new Student();stuObj.setName("solo");Assert.assertEquals(stuObj.getName(), "solo"); }}
编写好测试代码后,可以右键执行:
3) StudentDaoImplTest.java
package com.study.testngproj.entity.dao.impl;import org.testng.annotations.Test;import org.testng.AssertJUnit;import org.powermock.api.mockito.PowerMockito;import org.testng.Assert;import org.testng.annotations.BeforeTest;import org.testng.annotations.Test;import com.study.testngproj.entity.Student;import com.study.testngproj.entity.dao.impl.StudentDaoImpl;public class StudentDaoImplTest { private Student stuObj4Test; @BeforeTest public void init() {stuObj4Test = new Student();stuObj4Test.setGrade("4");stuObj4Test.setStuNumber(10);stuObj4Test.setName("solo");stuObj4Test.setBirthDay("19880418");stuObj4Test.setSexual("femal"); } @Test public void testQueryStudent( ) { //生成一个dao对象,查询number 为 7的student对象,并确认student对象的name是不是 solo StudentDaoImpl obj = PowerMockito.mock( StudentDaoImpl.class); PowerMockito.when(obj.queryStudent(10)).thenReturn(stuObj4Test); Student retObj = obj.queryStudent(10); Assert.assertNotNull( retObj); Assert.assertEquals(retObj.getName(), "solo"); }}4) DBOptTest.java 测试静态类
package com.study.testngproj.dbutil;import static org.testng.Assert.assertEquals;import org.testng.annotations.BeforeTest;import org.testng.annotations.Test;import java.util.ArrayList;import java.util.List;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.reflect.Whitebox;@PrepareForTest(DBUtil.class)public class DBOptTest { private DBOpt dbopt; @BeforeTest public void init() throws Exception{ dbopt = new DBOpt(); } @Test public void testQueryStudentByNumFromDBWithMock(){DBUtil instanceMock = PowerMockito.mock( DBUtil.class );Whitebox.setInternalState(DBUtil.class , "singleton", instanceMock);String tmp ="Number=7;Name=solo;Birthday=20071001;Grade=4;Sexual=male";List retList = new ArrayList();DBOpt retDBOpt = new DBOpt();retDBOpt.setStuBirthDay("20071001");retDBOpt.setStuGrade("4");retDBOpt.setStuName("solo");retDBOpt.setStuSexual("male");retDBOpt.setStuNumber(7);retList.add(retDBOpt); PowerMockito.when(instanceMock.queryForList("queryStudentByNumFromDB", dbopt) ).thenReturn(retList);List myList =new ArrayList();myList = dbopt.queryStudentByNumFromDB(7);int count = myList.size();assertEquals(count, 1);System.out.println("output"+myList.get(0));assertEquals( tmp, myList.get(0)); }}四:测试代码调试
1) 在单个类上,可以右键点击TestNg Test
如果代码没有错误,IDE打印如下内容:
[RemoteTestNG] detected TestNG version 6.12.0PASSED: studentCreate=============================================== Default test Tests run: 1, Failures: 0, Skips: 0==============================================================================================Default suiteTotal tests run: 1, Failures: 0, Skips: 0===============================================
2) 可以利用testng.xml 进行测试类的整体测试
通过Run Configurations,指定testng.xml
运行完成后,提示如下
=====Creating E:\cwqwork\eclipse_workspace\StudyTestNg\test-output\Suite\Test.htmlCreating E:\cwqwork\eclipse_workspace\StudyTestNg\test-output\Suite\Test.xmlPASSED: testQueryStudentPASSED: studentCreatePASSED: testCreateStudentWithMockPASSED: testQueryStudentByNumFromDBWithMock=============================================== Test Tests run: 4, Failures: 0, Skips: 0==============================================================================================SuiteTotal tests run: 4, Failures: 0, Skips: 0===============================================
五、异常
1、测试静态类提示错误
FAILED: testQueryStudentByNumFromDBWithMockorg.powermock.api.mockito.ClassNotPreparedException: [Ljava.lang.Object;@1b0b4509The class com.study.testngproj.dbutil.DBUtil not prepared for test.
这个异常比较诡异,在myeclipse2015里面没有问题,在eclipse下一直有这个问题,通过在testng.xml 中加入
<suite name="Suite" verbose="10" parallel="false"
object-factory="org.powermock.modules.testng.PowerMockObjectFactory">
- Devops学习实践(六) Eclipse集成TestNg,mock编写单元测试
- Devops学习实践(三) jenkins集成findbugs
- Devops学习实践(七)Jenkins 集成 Sonar
- Devops学习实践(四) jenkins通过maven或ant集成checkstyle
- testNG单元测试学习
- spring test集成resteasy mock单元测试
- 单元测试中mock的使用及mock神器jmockit实践
- 单元测试中mock的使用及mock神器jmockit实践
- 有效使用Mock编写java单元测试
- 有效使用Mock编写java单元测试
- 有效使用Mock编写java单元测试
- 单元测试之TestNG与spring集成
- 单元测试框架testNG学习笔记
- DevOps企业实践指南(6): 持续集成
- Eclipse中怎么安装TestNG单元测试框架
- Devops学习实践(一) SVN安装和配置
- Devops学习实践(二) Jenkins安装、配置、任务构建
- Spring MVC的单元测试和集成测试(不使用mock)
- 【Unity Shader】用shader控制背景的倾斜渐变
- Android Activity启动模式分析
- PullToRefreshListView,上啦刷新和下拉
- iOS开发学习之大牛们的博客
- Java对象校验框架之Oval
- Devops学习实践(六) Eclipse集成TestNg,mock编写单元测试
- HashMap实现原理分析
- 【MySQL】20个经典面试题,全部答对月薪10k+
- 四种聚类算法
- 学习总结之JavaWeb实现分页
- ICS Return 1 when x contains an odd number of 1s,0 otherwise(判断二进制表示中1的个数是否为奇数)
- BZOJ2705[Longge的问题] 欧拉函数
- linux 内核代码分析1 TI am335x
- iOS开发常用国外网站清单