第一步:pom依赖
<!-- 单元测试 --> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-core</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-dbunit</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-io</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-database</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-spring</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.5.3</version> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.5.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>RELEASE</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-core</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-dbunit</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-io</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-database</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-spring</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.5.3</version> </dependency>
第二步:编写关于unitils的4个工具类,我现在放在unitils包下
package com.odianyun.back.order.web.unitils;
import java.io.File;
import java.util.Arrays;
import java.util.Properties;
import org.unitils.core.UnitilsException;
import org.unitils.dbunit.datasetfactory.DataSetFactory;
import org.unitils.dbunit.util.MultiSchemaDataSet;
public class MultiSchemaXlsDataSetFactory implements DataSetFactory {
protected String defaultSchemaName;
public void init(Properties configuration, String s) {
this.defaultSchemaName = s;
}
public MultiSchemaDataSet createDataSet(File... dataSetFiles) {
try {
MultiSchemaXlsDataSetReader xlsDataSetReader = new MultiSchemaXlsDataSetReader(defaultSchemaName);
return xlsDataSetReader.readDataSetXls(dataSetFiles);
} catch (Exception e) {
throw new UnitilsException("创建数据集失败:" + Arrays.toString(dataSetFiles), e);
}
}
public String getDataSetFileExtension() {
return "xls";
}
}
package com.odianyun.unitils; import org.dbunit.database.AmbiguousTableNameException; import org.dbunit.dataset.DefaultDataSet; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.ITable; import org.dbunit.dataset.excel.XlsDataSet; import org.unitils.core.UnitilsException; import org.unitils.dbunit.util.MultiSchemaDataSet; import java.io.File; import java.io.FileInputStream; import java.util.*; public class MultiSchemaXlsDataSetReader { private String pattern = "."; private String defaultSchemaName; public MultiSchemaXlsDataSetReader(String defaultSchemaName) { this.defaultSchemaName = defaultSchemaName; } public MultiSchemaDataSet readDataSetXls(File... dataSetFiles) { try { Map<String, List<ITable>> tbMap = getTables(dataSetFiles); MultiSchemaDataSet dataSets = new MultiSchemaDataSet(); for (Map.Entry<String, List<ITable>> entry : tbMap.entrySet()) { List<ITable> tables = entry.getValue(); try { DefaultDataSet ds = new DefaultDataSet(tables.toArray(new ITable[]{})); dataSets.setDataSetForSchema(entry.getKey(), ds); } catch (AmbiguousTableNameException e) { throw new UnitilsException("构造DataSet失败!", e); } } return dataSets; } catch (Exception e) { throw new UnitilsException("解析Excel文件出错:", e); } } private Map<String, List<ITable>> getTables(File... dataSetFiles) { Map<String, List<ITable>> tableMap = new HashMap(); // 需要根据schema把Table重新组合一下 try { String schema, tableName; for (File file : dataSetFiles) { IDataSet dataSet = new XlsDataSet(new FileInputStream(file)); String[] tableNames = dataSet.getTableNames(); for (String tn : tableNames) { String[] temp = tn.split(pattern); if (temp.length == 2) { schema = temp[0]; tableName = temp[1]; } else { schema = this.defaultSchemaName; tableName = tn; } ITable table = dataSet.getTable(tn); if (!tableMap.containsKey(schema)) { tableMap.put(schema, new ArrayList<ITable>()); } tableMap.get(schema).add(new XslTableWrapper(tableName, table)); } } } catch (Exception e) { throw new UnitilsException("Unable to create DbUnit dataset for data set files: " + Arrays.toString(dataSetFiles), e); } return tableMap; } }
package com.odianyun.unitils; import org.dbunit.database.DatabaseConfig; import org.dbunit.ext.mysql.MySqlDataTypeFactory; import org.dbunit.ext.mysql.MySqlMetadataHandler; import org.unitils.core.UnitilsException; import org.unitils.dbmaintainer.locator.ClassPathDataLocator; import org.unitils.dbmaintainer.locator.resourcepickingstrategie.ResourcePickingStrategie; import org.unitils.dbunit.DbUnitModule; import org.unitils.dbunit.datasetfactory.DataSetFactory; import org.unitils.dbunit.util.DbUnitDatabaseConnection; import org.unitils.dbunit.util.MultiSchemaDataSet; import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.List; public class MyDbUnitModule extends DbUnitModule { //完善DbUnitDatabaseConnection连接信息 @Override public DbUnitDatabaseConnection getDbUnitDatabaseConnection(final String schemaName) { DbUnitDatabaseConnection result = dbUnitDatabaseConnections.get(schemaName); if (result != null) { return result; } result = super.getDbUnitDatabaseConnection(schemaName); result.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory()); result.getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler()); return result; } //Excel预处理操作,将@DataSet注释读取的文件返回给DataSetFactory进行处理 @Override protected File handleDataSetResource(ClassPathDataLocator locator, String nameResource, ResourcePickingStrategie strategy, Class<?> testClass) { String cloneResource = new String(nameResource); String packageName = testClass.getPackage() != null?testClass.getPackage().getName():""; String tempName = ""; if(cloneResource.startsWith(packageName.replace(".", "/"))) { cloneResource = tempName = cloneResource.substring(packageName.length()); } else if(cloneResource.startsWith(packageName)) { cloneResource = tempName = cloneResource.substring(packageName.length() + 1); } else { tempName = cloneResource; } InputStream in = locator.getDataResource(packageName.replace(".", "/") + "/" + tempName, strategy); File resolvedFile = null; if(in == null) { resolvedFile = this.getDataSetResolver().resolve(testClass, cloneResource); if(resolvedFile == null) { throw new UnitilsException("DataSetResource file with name ‘" + nameResource + "‘ cannot be found"); } } return resolvedFile; } //调用DataSetFactory.createDataSet()向数据库中注入Excel数据后,直接返回DataSet,不对DataSet执行清零操作 @Override protected MultiSchemaDataSet getDataSet(Class<?> testClass, String[] dataSetFileNames, DataSetFactory dataSetFactory) { List<File> dataSetFiles = new ArrayList<File>(); ResourcePickingStrategie resourcePickingStrategie = getResourcePickingStrategie(); for (String dataSetFileName : dataSetFileNames) { File dataSetFile = handleDataSetResource(new ClassPathDataLocator(), dataSetFileName, resourcePickingStrategie, testClass); dataSetFiles.add(dataSetFile); } MultiSchemaDataSet dataSet = dataSetFactory.createDataSet(dataSetFiles.toArray(new File[dataSetFiles.size()])); return dataSet; } }
package com.odianyun.unitils;
import org.apache.commons.lang.StringUtils;
import org.dbunit.dataset.*;
import org.unitils.core.UnitilsException;
class XslTableWrapper extends AbstractTable {
private ITable delegate;
private String tableName;
public XslTableWrapper(String tableName, ITable table) {
this.delegate = table;
this.tableName = tableName;
}
public int getRowCount() {
return delegate.getRowCount();
}
public ITableMetaData getTableMetaData() {
ITableMetaData meta = delegate.getTableMetaData();
try {
return new DefaultTableMetaData(tableName, meta.getColumns(), meta.getPrimaryKeys());
} catch (DataSetException e) {
throw new UnitilsException("Don‘t get the meta info from " + meta, e);
}
}
public Object getValue(int row, String column) throws DataSetException {
Object delta = delegate.getValue(row, column);
if (delta instanceof String) {
if (StringUtils.isEmpty((String) delta)) {
return null;
}
}
return delta;
}
}
第三步:在test下创建一个dbscripts的sql的ddl文件
我就随便到处了数据结构的
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_bin DEFAULT NULL,
`status` int(2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
第四步:配置
unitils.modules=database,dbunit,spring #自定义扩展模块,加载Excel文件,默认拓展模块org.unitils.dbunit.DbUnitModule支持xml #unitils.module.dbunit.className=org.unitils.dbunit.DbUnitModule unitils.module.dbunit.className=com.odianyun.unitils.MyDbUnitModule #配置数据库连接 database.driverClassName=com.mysql.jdbc.Driver database.url=jdbc:mysql://127.0.0.1:3306/dbtest?autoReconnect=true&useUnicode=true&characterEncoding=utf-8 database.userName=root database.password=root #配置为数据库名称 database.schemaNames=dbtest #配置数据库方言 database.dialect=mysql #需设置false,否则我们的测试函数只有在执行完函数体后,才将数据插入的数据表中 unitils.module.database.runAfter=false #配置数据库维护策略.请注意下面这段描述 # If set to true, the DBMaintainer will be used to update the unit test database schema. This is done once for each # test run, when creating the DataSource that provides access to the unit test database. updateDataBaseSchema.enabled=true #配置数据库表创建策略,是否自动建表以及建表sql脚本存放目录 dbMaintainer.autoCreateExecutedScriptsTable=true dbMaintainer.keepRetryingAfterError.enabled=true dbMaintainer.script.locations=src/test/resources/dbscripts #dbMaintainer.script.fileExtensions=sql #数据集加载策略 #CleanInsertLoadStrategy:先删除dateSet中有关表的数据,然后再插入数据 #InsertLoadStrategy:只插入数据 #RefreshLoadStrategy:有同样key的数据更新,没有的插入 #UpdateLoadStrategy:有同样key的数据更新,没有的不做任何操作 DbUnitModule.DataSet.loadStrategy.default=org.unitils.dbunit.datasetloadstrategy.impl.CleanInsertLoadStrategy #配置数据集工厂,自定义 DbUnitModule.DataSet.factory.default=com.odianyun.unitils.MultiSchemaXlsDataSetFactory DbUnitModule.ExpectedDataSet.factory.default=com.odianyun.unitils.MultiSchemaXlsDataSetFactory #配置事务策略 commit、rollback 和disabled;或者在代码的方法上标记@Transactional(value=TransactionMode.ROLLBACK) #commit 是单元测试方法过后提交事务 #rollback 是回滚事务 #disabled 是没有事务,默认情况下,事务管理是disabled DatabaseModule.Transactional.value.default=commit #配置数据集结构模式XSD生成路径,可以自定义目录,但不能为空 dataSetStructureGenerator.xsd.dirName=src/test/resources/xsd dbMaintainer.generateDataSetStructure.enabled=true #文件相对路径是否是测试类文件路径,false表示resource根目录 dbUnit.datasetresolver.prefixWithPackageName=false
第五步:创建BaseUnitsTest类
package com.test;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.unitils.UnitilsJUnit4TestClassRunner;
/**
* @author 危常焕
* @time 2017/11/28
* @description https://github.com/newsoulbr/mokitopoc/blob/master/src/test/java/com/github/newsoulbr/mokitopoc/service/PersonServiceTest.java
* http://www.unitils.org/tutorial-reflectionassert.html
* http://blog.csdn.net/achuo/article/details/47726241
*
*/
@RunWith(UnitilsJUnit4TestClassRunner.class)
public class BaseUnitilsTest {
protected static ApplicationContext ctx;
protected static ConfigurableApplicationContext configurableContext;
protected static BeanDefinitionRegistry beanDefinitionRegistry;
@BeforeClass
public static void setUpBeforeClass() {
ctx = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml");
configurableContext = (ConfigurableApplicationContext) ctx;
beanDefinitionRegistry = (DefaultListableBeanFactory) configurableContext.getBeanFactory();
}
public static void registerBean(String beanId, String className) {
// get the BeanDefinitionBuilder
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(className);
// get the BeanDefinition
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// register the bean
beanDefinitionRegistry.registerBeanDefinition(beanId, beanDefinition);
}
/**
* 移除bean
*
* @param beanId
* bean的id
*/
public static void unregisterBean(String beanId) {
beanDefinitionRegistry.removeBeanDefinition(beanId);
}
}
第六步:准备excel:sheet是代表表名:第一列是列名:一行是一个对象
第七步:测试
package com.test;
import com.po.SysRoleResource;
import com.service.SysRoleResourceService;
import com.service.impl.SysRoleResourceServiceImpl;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unitils.dbunit.annotation.DataSet;
public class TestDemo2 extends BaseUnitilsTest {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private SysRoleResourceService sysRoleResourceService;
@Before
public void setUp() {
sysRoleResourceService = (SysRoleResourceService) ctx.getBean(SysRoleResourceServiceImpl.class);
}
@Test
@DataSet(value = { "excel\\demo.xls" })
// 通过Unitils提供的@DataSet注解从当前测试类this.class所在的目录寻找支持DbUnit的数据集文件并进行加载。
// 执行测试逻辑之前,会把加载的数据集先持久化到测试数据库中,
// @ExpectedDataSet(value = {
// "com\\odianyun\\demo\\dao\\WarehouseDAOTestdemo.xls" })
// 是在单元测试之后进行数据比对
// 从当前测试类this.class所在的目录寻找支持DbUnit的验证数据集文件并进行加载,
// 之后验证数据集里的数据和数据库中的数据是否一致
public void selectByPrimaryKey() {
SysRoleResource selectByPrimaryKey = sysRoleResourceService.selectByPrimaryKey(1);
System.err.println(selectByPrimaryKey.getRoleId());
logger.debug(selectByPrimaryKey.getRoleId() + "");
};
}