您的位置:首页 > 其它

【让开发自动化】Unitils与DBUnit 兼容性问题

2013-07-30 00:00 453 查看
由于系统里用到了POI-3.5.FINAL用于Excel的处理,而unitils配套的DBUnit才2.2版本,与POI-3.5版本冲突,需要升级DBUnit的版本。目测最新版为2.4.9,与POI-3.5正好配套,一运行,出现如下异常:

org.unitils.core.UnitilsException: Error inserting test data from DbUnit dataset for method public void com.litt.cidp.system.service.OperatorServiceTest.test_load()
at org.unitils.dbunit.DbUnitModule.insertDataSet(DbUnitModule.java:156)
at org.unitils.dbunit.DbUnitModule$DbUnitListener.beforeTestSetUp(DbUnitModule.java:557)
at org.unitils.core.Unitils$UnitilsTestListener.beforeTestSetUp(Unitils.java:273)
at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runBeforesThenTestThenAfters(UnitilsJUnit4TestClassRunner.java:151)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.unitils.UnitilsJUnit4TestClassRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:95)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61)
at org.unitils.UnitilsJUnit4TestClassRunner.access$000(UnitilsJUnit4TestClassRunner.java:44)
at org.unitils.UnitilsJUnit4TestClassRunner$1.run(UnitilsJUnit4TestClassRunner.java:62)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:68)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.unitils.core.UnitilsException: Error while executing DataSetLoadStrategy
at org.unitils.dbunit.datasetloadstrategy.impl.BaseDataSetLoadStrategy.execute(BaseDataSetLoadStrategy.java:46)
at org.unitils.dbunit.DbUnitModule.insertDataSet(DbUnitModule.java:230)
at org.unitils.dbunit.DbUnitModule.insertDataSet(DbUnitModule.java:153)
... 18 more
Caused by: org.dbunit.dataset.NoSuchColumnException: operator.OP_ID -  (Non-uppercase input column: OP_ID) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.
at org.dbunit.dataset.AbstractTableMetaData.getColumnIndex(AbstractTableMetaData.java:117)
at org.dbunit.operation.AbstractOperation.getOperationMetaData(AbstractOperation.java:89)
at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:143)
at org.unitils.dbunit.datasetloadstrategy.impl.InsertLoadStrategy.doExecute(InsertLoadStrategy.java:45)
at org.unitils.dbunit.datasetloadstrategy.impl.BaseDataSetLoadStrategy.execute(BaseDataSetLoadStrategy.java:44)
... 20 more

中间过程就不赘述了,直接看问题根源org.dbunit.database.DatabaseTableMetaData。其内部 Column[] _columns未被正确初始化 ,导致最终dbunit数据操作失败。跟踪代码可以看到是metadataHandler.matches出了问题,在进一步跟踪我们可以看到,这个方法传入了ResultSet和schemaName用于对象识别,然而从ResultSet中获得的schemaName为空,匹配识别,导致Column获取失败。

public Column[] getColumns() throws DataSetException
{
logger.debug("getColumns() - start");

if (_columns == null)    //这里获得的是一个长度为0的数组,不为空
{
...

List columnList = new ArrayList();
while (resultSet.next())
{
// Check for exact table/schema name match because
// databaseMetaData.getColumns() uses patterns for the lookup

//这里的match没有匹配到
boolean match = metadataHandler.matches(resultSet, schemaName, tableName, _caseSensitiveMetaData);
if(match)
{
Column column = SQLHelper.createColumn(resultSet, dataTypeFactory, datatypeWarning);
if(column != null)
{
columnList.add(column);
}
}
else
{
logger.debug("Skipping <schema.table> '" + resultSet.getString(2) + "." +
resultSet.getString(3) + "' because names do not exactly match.");
}
}

if (columnList.size() == 0)
{
logger.warn("No columns found for table '"+ tableName +"' that are supported by dbunit. " +"Will return an empty column list");
}

public boolean matches(ResultSet columnsResultSet, String catalog,
String schema, String table, String column,
boolean caseSensitive) throws SQLException
{
if(logger.isTraceEnabled())
logger.trace("matches(columnsResultSet={}, catalog={}, schema={}," +
" table={}, column={}, caseSensitive={}) - start",
new Object[] {columnsResultSet, catalog, schema,
table, column, Boolean.valueOf(caseSensitive)});

String catalogName = columnsResultSet.getString(1);
String schemaName = columnsResultSet.getString(2);  //这里获得的schemaName为空
String tableName = columnsResultSet.getString(3);
String columnName = columnsResultSet.getString(4);

if(logger.isDebugEnabled()){
logger.debug("Comparing the following values using caseSensitive={} (searched<=>actual): " +
"catalog: {}<=>{} schema: {}<=>{} table: {}<=>{} column: {}<=>{}",
new Object[] {
Boolean.valueOf(caseSensitive),
catalog, catalogName,
schema, schemaName,
table, tableName,
column, columnName
});
}

boolean areEqual =
areEqualIgnoreNull(catalog, catalogName, caseSensitive) &&
areEqualIgnoreNull(schema, schemaName, caseSensitive) &&
areEqualIgnoreNull(table, tableName, caseSensitive) &&
areEqualIgnoreNull(column, columnName, caseSensitive);
return areEqual;
}

经进一步核实,DBUnit新版本中的处理方式与老版本不同,老版本中使用了SQLHelper并处理了MySql,schema的问题,新版本中需要指定metadataHandler的实现类,而Unitils由于配套的仅为2.2版本,暂不支持该配置方式。

解决方案:

将dbunit降级到2.4.2版本;

或修改unitils的源码;

BUG追踪:https://unitils.atlassian.net/browse/UNI-152
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息