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

我与影子孤独终老i 提交于 2019-11-27 17:31:52

由于系统里用到了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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!