由于系统里用到了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版本,暂不支持该配置方式。
解决方案:
BUG追踪:https://unitils.atlassian.net/browse/UNI-152