meavn+spring+testng+mybatis+dbunit进行单元测试

前段时间做项目对整接口做集成测试,使用meavn+spring+testng+mybatis+dbunit对接口进行测试。

1先测试一个普通的树结构加载,不带参数,从数据库中读取树结构。

public interface TreeService {
	Map getTree();	
}

testng提供接口AbstractTestNGSpringContextTests,可以将项目配置文件导入。

@ContextConfiguration(locations = {"classpath*:applicationContext.xml","classpath*:mybatis-config.xml"})
public class TreeServiceImplTest extends AbstractTestNGSpringContextTests{	
	Map map;
	String retStr = "";
	@Autowired
	private TreeService treeservice;
	@Test(threadPoolSize = 3, invocationCount = 2,  timeOut = 100000)
	public void getTree() {
		map = treeservice.getTree();
		retStr = JSONObject.toJSONString(map).toString();
		System.out.println(retStr);
		Assert.assertNotNull(retStr);
		Assert.assertEquals("{\"count\":10,\"data\":\"123\",\"respCode\":1,\"respDesc\":\"test1234\"}", retStr);
	}
}

2更新函数的测试中需要向数据库中写入更新的参数,这个每次更新都会对数据库进行改变,很难保证第一次测试的操作会不会影响到第二次测试,所以使用dbunit完成数据库的备份和恢复。dbunit是一个基于junit扩展的数据库测试框架。它提供了大量的类对与数据库相关的操作进行了抽象和封装。为依赖于其他外部系统(如数据库或其他接口)的代码编写单元测试是一件很困难的工作。在这种情况下,有效的单元必须隔离测试对象和外部依赖,以便管理测试对象的状态和行为。使用mock object对象,是隔离外部依赖的一个有效方法。如果我们的测试对象是依赖于DAO的代码,mock object技术很方便。如果测试对象变成了DAO本身或者集成测试,就需要对实际的数据库进行操作。

public interface AppRankService {
	boolean updateAppRankById(String json,String id);
}

使用dbunit的时候先封装两个方法一个备份数据库,一个回滚,因为数据库中存在null,而dbunit认为null中数值为错误,所以需要配置忽略空值。

public class DbUnitService extends DBTestCase {
	private final Logger log = Logger.getLogger(getClass());
	String dir_name = "dbbackup";//备份到文件夹
	//配置测试库
	public DbUnitService() {
		String dbusername = "root";
		String dbpassword = "root";
		String dbtype = "mysql";
		String dburl = "jdbc:mysql://192.168.12.163:3306/mquery_test?characterEncoding=UTF-8";
		createDir(dir_name);
		if (dbtype.equals("mysql")) {
			System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "com.mysql.jdbc.Driver");
		} else {
			log.error("undefined db type !");
		}
		System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, dburl);
		System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, dbusername);
		System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, dbpassword);
	}
	//备份单张表
		public void backupTable(String tbname, String xmlFileName) throws Exception {
		IDatabaseConnection connection = getConnection();
		try {

			QueryDataSet dataSet = new QueryDataSet(connection);
			dataSet.addTable(tbname);
			File f_file = new File(dir_name + File.separator + xmlFileName);
			FlatXmlDataSet.write(dataSet, new FileOutputStream(f_file));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (connection != null)
					connection.close();
			} catch (SQLException e) {
			}
		}
	}
	//回滚操作	
		public void rollback(String xmlFileName) throws Exception {
		IDatabaseConnection connection = getConnection();
		connection.getConfig().setFeature(DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS, true);
		try {
			FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
			builder.setColumnSensing(true);
			IDataSet ds = builder.build(new FileInputStream(new File(dir_name + File.separator + xmlFileName)));
			// recover database
			DatabaseOperation.CLEAN_INSERT.execute(connection, ds);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (connection != null)
					connection.close();
			} catch (SQLException e) {
			}
		}
	}
}

测试用例中使用两种方式,一种用sql语句进行精确校验,使用testng的断言函数比较查询结果和期望值,另外一种使用dbunit的Assertion.assertEquals函数比较两个表,在更新操作后,首先读取数据存入一个临时表dbTable中,然后从xml文件中读取期望结果的表存入xmlTable中,然后对比两个表,可以使用includedColumnsTable包含某些列,也可以使用excludedColumnsTable排除某些列后比较剩下的列。两种方式各有优势,sql语句的方式更灵活一些,Assertion需要对整个表的行数,和某列进行对比,所以占用资源更多,但是某些dbunit官方认为对数据库操作的时候需要校验整个表的内容,以保证本次操作不对额外的行破坏。

@ContextConfiguration(locations = {"classpath*:applicationContext.xml","classpath*:mybatis-config.xml"})
public class AppRankServiceImplTest extends AbstractTestNGSpringContextTests  {
	public String app_link_ip;
	public int rank;
	public String id;
	public String app_id;
	DatabaseService ds = new DatabaseService();
	Connection conn = null;
	DbUnitService dbunit = new DbUnitService();
	@Autowired
	private AppRankService appRankService;
	@Test(threadPoolSize = 10, invocationCount = 20,  timeOut = 100000)
	public void updateAppRankById() throws Exception {
		HashMap promap = new HashMap();
		long id = Thread.currentThread().getId();
		promap.put("app_link_ip", "test_dbunit");
		promap.put("rank", ranknum++);
		promap.put("app_link_domain", uuidstr);
		String testStr = JSONObject.toJSONString(promap).toString();
		//执行被测方法,updateAppRankById操作数据库
		boolean retboolen = appRankService.updateAppRankById(testStr, "b3b3310f0e0a466893c39cfc431bcac2");
		Assert.assertTrue(retboolen);//检查是否可以成功执行update操作
		String sql = "SELECT app_link_ip FROM app_rank_source WHERE id = \"b3b3310f0e0a466893c39cfc431bcac2\"";
		String retstr = ds.getData(conn, sql, 1, 1);//通过sql语句检查更新字段是否成功被改变
		Assert.assertEquals(retstr, "test_dbunit");
	}
	@Test(threadPoolSize = 10, invocationCount = 20,  timeOut = 100000)
	public void updateAppRankById2() throws Exception {
		HashMap promap = new HashMap();
		promap.put("app_link_ip", "test_dbunit");
		promap.put("rank", 1);
		String testStr = JSONObject.toJSONString(promap).toString();
		boolean retboolen = appRankService.updateAppRankById(testStr, "b3b3310f0e0a466893c39cfc431bcac2");
		Assert.assertTrue(retboolen);//判断是否执行成功
		//从真实表app_rank_source中读取数据存在临时表dbTable中
		IDataSet dbDataSet = dbunit.getDBDataSet();	
		ITable dbTable =dbDataSet.getTable("app_rank_source"); 
		//从test_resource中获取期望结果,期望结果存储在xml中,读取,放到临时表xmlTable中
		IDataSet xmlDataSet =dbunit.getXmlDataSet("app_rank_source.xml"); 
		ITable xmlTable = replacementDataSet.getTable("app_rank_source");	  
		//比较某列或几列,或者使用excludedColumnsTable排除某列
		dbTable=DefaultColumnFilter.includedColumnsTable(dbTable, new String[]{"app_link_ip"}); 
		xmlTable =DefaultColumnFilter.includedColumnsTable(xmlTable, new String[]{"app_link_ip"});
//		Assert.assertEquals(dbTable.getRowCount(),xmlTable.getRowCount());//比较行数
		Assertion.assertEquals(dbTable, xmlTable); 
	}
	@BeforeTest
	public void beforeClass() throws Exception {
		conn = ds.connectDBDriver("mysql", "root", "root",
				"jdbc:mysql://192.168.12.163:3306/mquery_test?characterEncoding=UTF-8");
		dbunit.backupTable("app_rank_source","tables.xml");//备份表
	}
	@AfterTest
	public void afterClass() throws Exception {
		dbunit.rollback("tables.xml");//还原表
		ds.closeDBDriver(conn);
	}
}

你可能感兴趣的:(测试开发)