说明:这里的多数据源需要利用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>