让Unitils实现excel上的多数据源支持
让Unitils实现excel下的多数据源支持
说明:这里的多数据源需要利用spring中配置的多个DataSource.而且仅针对oracle数据库. 在oracle有一个schema的概念, 一个datasource下可能有多个schema, 而一个schema一般会跟一组用户名密码绑定, 这里我们采用用户名作为schema名称.
为了实现对多schema的支持, unitils提供了一个MultiSchemaXmlDataSetFactory, 也就是在采用xml的格式来实现多数据源的创建, 但不知道为什么原因, 没有提供对excel格式的多schema的支持, 而对于所有测试都采用excel来构造测试数据用户来说, 则显得有些无奈, 为了实现这个功能, 了解了一下unitils-dbunit, dbunit相关的源代码, 不过有些困难, 一个是dbunit提供的接口对我们的扩展有一些限制. 比如我们希望我们在excel中定义测试数据的时候, 每个sheet的名称将采用"datasourceName.tablename"的约定来定义. 因此我们必须在解析excel文件的时候, 必须从中已有的table中解析出datasource和tablename.
废话少说, 其具体做法是: 在从excel中取得DataSet之后(一个excel对应一个DataSet, 一个Sheet对应一个Table), 将DataSet中的所有Table根据datasource名称进行重组, 然后将得到的多个DataSet用MultiSchemaDataSet进行封装. 而MultiSchemaXlsDataSetFactory类的工作就是为了创建这个MultiSchemaDataSet.
为了对XslTable重新进行封装, 使用了下面的类来处理去掉datasource后的tablename, 因为在执行过程中ITableMetaData会使用到表名, 而这个表名我们是没办法通过继承来进行修改的, 只能通过代理的形式了.
另外目前本人使用的unitls版本为3.1, 而在其内部依赖的dbunit版本为2.2.2, 这个版本使用解析excel的poi版本在处理excel中cell的格式为日期的时候, 会有问题, 需要指定一下dbunit的最新版本2.4.6, 在maven中的依赖配置:
晕了,dbunit本来就是为了不破坏数据库现场才使用的测试工具,测试结束后就回滚了
说明:这里的多数据源需要利用spring中配置的多个DataSource.而且仅针对oracle数据库. 在oracle有一个schema的概念, 一个datasource下可能有多个schema, 而一个schema一般会跟一组用户名密码绑定, 这里我们采用用户名作为schema名称.
为了实现对多schema的支持, unitils提供了一个MultiSchemaXmlDataSetFactory, 也就是在采用xml的格式来实现多数据源的创建, 但不知道为什么原因, 没有提供对excel格式的多schema的支持, 而对于所有测试都采用excel来构造测试数据用户来说, 则显得有些无奈, 为了实现这个功能, 了解了一下unitils-dbunit, dbunit相关的源代码, 不过有些困难, 一个是dbunit提供的接口对我们的扩展有一些限制. 比如我们希望我们在excel中定义测试数据的时候, 每个sheet的名称将采用"datasourceName.tablename"的约定来定义. 因此我们必须在解析excel文件的时候, 必须从中已有的table中解析出datasource和tablename.
废话少说, 其具体做法是: 在从excel中取得DataSet之后(一个excel对应一个DataSet, 一个Sheet对应一个Table), 将DataSet中的所有Table根据datasource名称进行重组, 然后将得到的多个DataSet用MultiSchemaDataSet进行封装. 而MultiSchemaXlsDataSetFactory类的工作就是为了创建这个MultiSchemaDataSet.
/** * 需要在unitils.properties文件中将<tt>DbUnitModule.DataSet.factory.default</tt>属性名设置为该类全限定名. * * @author lengda * @since 2009-12-3 下午04:15:29 */ public class MultiSchemaXlsDataSetFactory implements DataSetFactory { private static Pattern pattern = Pattern.compile("\\."); protected String defaultSchemaName; public void init(Properties configuration, String defaultSchemaName) { this.defaultSchemaName = defaultSchemaName; } public MultiSchemaDataSet createDataSet(File... dataSetFiles) { Map<String, List<ITable>> tableMap = getTables(dataSetFiles); MultiSchemaDataSet dataSets = new MultiSchemaDataSet(); for (Entry<String, List<ITable>> entry : tableMap.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(String.format("使用指定表[%s]重新构造DataSet失败", tables), e); } } return dataSets; } private Map<String, List<ITable>> getTables(File... dataSetFiles) { Map<String, List<ITable>> tableMap = new HashMap<String, List<ITable>>(); // 需要根据schema把Table重新组合一下 try { for (File file : dataSetFiles) { IDataSet dataSet = new XlsDataSet(new FileInputStream(file)); String[] tableNames = dataSet.getTableNames(); for (String each : tableNames) { // 这个实际上不是schema, 是对应的spring的datasouceId String schema = null; String tableName; String[] temp = pattern.split(each); if (temp.length == 2) { schema = temp[0]; tableName = temp[1]; } else { schema = this.defaultSchemaName; tableName = each; } ITable table = dataSet.getTable(each); 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; } public String getDataSetFileExtension() { return "xls"; } }
为了对XslTable重新进行封装, 使用了下面的类来处理去掉datasource后的tablename, 因为在执行过程中ITableMetaData会使用到表名, 而这个表名我们是没办法通过继承来进行修改的, 只能通过代理的形式了.
/** * 为了获得strip datasource后的表名 * * @author lengda * @since 2009-12-3 下午06:44:36 */ 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; } }
另外目前本人使用的unitls版本为3.1, 而在其内部依赖的dbunit版本为2.2.2, 这个版本使用解析excel的poi版本在处理excel中cell的格式为日期的时候, 会有问题, 需要指定一下dbunit的最新版本2.4.6, 在maven中的依赖配置:
<dependency> <groupId>org.unitils</groupId> <artifactId>unitils-dbunit</artifactId> <version>${unitils.version}</version> <exclusions> <exclusion> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.1-FINAL</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.4.6</version> <scope>compile</scope> </dependency>
1 楼
zfanxu
2012-05-03
请问,为什么我在MYSQL数据库下,运行的你的代码,程序不报错,但是数据也没插入到数据库中?
2 楼
mojunbin
2012-05-10
"StringUtils"这个类是org.apache.commons.lang.StringUtils否?
3 楼
kkeli
2012-06-11
zfanxu 写道
请问,为什么我在MYSQL数据库下,运行的你的代码,程序不报错,但是数据也没插入到数据库中?
晕了,dbunit本来就是为了不破坏数据库现场才使用的测试工具,测试结束后就回滚了