- 浏览: 1517682 次
- 性别:
- 来自: 厦门
博客专栏
-
Spring 3.x企业实...
浏览量:461683
文章分类
最新评论
-
JyeChou:
学习Spring必学的Java基础知识(1)----反射 -
hhzhaoheng:
...
《Spring4.x企业应用开发实战》光盘资料下载 -
renlongnian:
//assertReflectionEquals(user1, ...
单元测试系列之3:测试整合之王Unitils -
骑着蜗牛超F1:
huang_yong 写道我的经验是,只需定义三层:1.ent ...
Spring的事务管理难点剖析(2):应用分层的迷惑 -
wangyudong:
工具地址貌似更新了哦https://github.com/Wi ...
几种常用的REST webservice客户端测试工具
dbunit经典的NoSuchColumnException解决之道
- 博客分类:
- 05_程序测试
抱怨
dbunit这么多人用,这个项目居然好像没有人在维护了,自动2012年9月release一个版本后,再没有更新了,寒心啊。
dbunit有一个大大的BUG,即会解释不了MySQL表的结构,在使用@DataSet准备数据时,会抛出类似如下的异常:
网上有很多痛苦的人在苦苦寻答案,但都依旧痛苦着...
http://zfanxu.iteye.com/blog/1508339
http://bbs.csdn.net/topics/310215234
其实这是dbunit的一个BUG,好像很多版本都有这个问题,报告说解决了,其实并没有解决。我使用最新的2.4.9的版本照样会抛出这个问题。
解决
碰到问题光抱怨是没有用的,又不能指望dbunit的作者改,只能自己着腾了。按照网上的几篇文章改了dbunit的源码,重新编译上传到自己的Maven私服上。终于解决了。
为了避免大家再重新更改编译,我把已经解译好的dbunit jar放在附件中,大家需要的话可以下载使用。
继续...
最近又在整基于DB2的unitils框架,发现又出现问题了,结果再次好好跟踪了unitils及dbunit的源码,终于有了颠覆性的重大发现:
原来网上一直说的是DBUNIT框架导致这个问题的说明是错误的,真正的错误是unitils框架的错误!!
因为DBUNIT已经为不同数据库提供了不同的接口实现:
而unitils(具体地说是DbUnitModule模块)不管你什么数据库,它统一使用这个类:
如果数据库不特殊,当然用DefaultMetadataHandler这个没有问题,如果特殊,则就取不到数据库的Metadata信息了,结果异常就发生了。
但是,目前的DBUnit的Db2MetadataHandler确实是有BUG的,所以我的解决方法是:
1)复写了unitils的DbUnitModule实现类;
2)复写了dbunit的Db2MetadataHandler实现类;
3)配置unitils的配置文件,应用这些自定义的实现类。
下面是MyDb2MetadataHandler的源码:
最后一步,更改unitils.properties的配置:
总结
采用前面的解决方案只能解决mysql的问题,且直接改dbunit的源码,是不好的方案,现在我把它废弃了,大家就不要了。
采用第二种方案吧,是优雅的解决方案,没有更改dbunit的源码,仅通过unitils的扩展配置实现了,所以你不要下载附件的dbunit-2.4.8.2.jar了,直接使用最新的dbunit版本吧:
这个问题啊,让我死几回的心都有了,现在终于解决了,希望对大家有帮助!
dbunit这么多人用,这个项目居然好像没有人在维护了,自动2012年9月release一个版本后,再没有更新了,寒心啊。
dbunit有一个大大的BUG,即会解释不了MySQL表的结构,在使用@DataSet准备数据时,会抛出类似如下的异常:
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) ... 35 more Caused by: org.dbunit.dataset.NoSuchColumnException: t_upload_file.ID - (Non-uppercase input column: 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:140) at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79) at org.unitils.dbunit.datasetloadstrategy.impl.CleanInsertLoadStrategy.doExecute(CleanInsertLoadStrategy.java:45) at org.unitils.dbunit.datasetloadstrategy.impl.BaseDataSetLoadStrategy.execute(BaseDataSetLoadStrategy.java:44) ... 37 more
网上有很多痛苦的人在苦苦寻答案,但都依旧痛苦着...
http://zfanxu.iteye.com/blog/1508339
http://bbs.csdn.net/topics/310215234
其实这是dbunit的一个BUG,好像很多版本都有这个问题,报告说解决了,其实并没有解决。我使用最新的2.4.9的版本照样会抛出这个问题。
解决
碰到问题光抱怨是没有用的,又不能指望dbunit的作者改,只能自己着腾了。按照网上的几篇文章改了dbunit的源码,重新编译上传到自己的Maven私服上。终于解决了。
为了避免大家再重新更改编译,我把已经解译好的dbunit jar放在附件中,大家需要的话可以下载使用。
继续...
最近又在整基于DB2的unitils框架,发现又出现问题了,结果再次好好跟踪了unitils及dbunit的源码,终于有了颠覆性的重大发现:
原来网上一直说的是DBUNIT框架导致这个问题的说明是错误的,真正的错误是unitils框架的错误!!
因为DBUNIT已经为不同数据库提供了不同的接口实现:
org.dbunit.database.IMetadataHandler
而unitils(具体地说是DbUnitModule模块)不管你什么数据库,它统一使用这个类:
org.dbunit.database.DefaultMetadataHandler
如果数据库不特殊,当然用DefaultMetadataHandler这个没有问题,如果特殊,则就取不到数据库的Metadata信息了,结果异常就发生了。
但是,目前的DBUnit的Db2MetadataHandler确实是有BUG的,所以我的解决方法是:
1)复写了unitils的DbUnitModule实现类;
2)复写了dbunit的Db2MetadataHandler实现类;
3)配置unitils的配置文件,应用这些自定义的实现类。
package com.ridge.test.unitils.ext; import org.dbunit.database.DatabaseConfig; import org.dbunit.database.DefaultMetadataHandler; import org.dbunit.dataset.DataSetException; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.datatype.IDataTypeFactory; import org.dbunit.dataset.filter.ITableFilterSimple; import org.dbunit.ext.db2.Db2DataTypeFactory; import org.dbunit.ext.db2.Db2MetadataHandler; import org.dbunit.ext.mysql.MySqlDataTypeFactory; import org.dbunit.ext.mysql.MySqlMetadataHandler; import org.unitils.core.UnitilsException; import org.unitils.core.dbsupport.DbSupport; import org.unitils.core.dbsupport.DefaultSQLHandler; import org.unitils.core.dbsupport.SQLHandler; import org.unitils.dbunit.DbUnitModule; import org.unitils.dbunit.util.DbUnitDatabaseConnection; import javax.sql.DataSource; import static org.dbunit.database.DatabaseConfig.FEATURE_BATCHED_STATEMENTS; import static org.dbunit.database.DatabaseConfig.PROPERTY_DATATYPE_FACTORY; import static org.dbunit.database.DatabaseConfig.PROPERTY_ESCAPE_PATTERN; import static org.unitils.core.dbsupport.DbSupportFactory.getDbSupport; import static org.unitils.core.util.ConfigUtils.getInstanceOf; /** * @author : chenxh(quickselect@163.com) * @date: 13-10-9 */ public class MyDbunitModule extends DbUnitModule { protected DbUnitDatabaseConnection createDbUnitConnection(String schemaName) { // A DbSupport instance is fetched in order to get the schema name in correct case DataSource dataSource = getDatabaseModule().getDataSourceAndActivateTransactionIfNeeded(); SQLHandler sqlHandler = new DefaultSQLHandler(dataSource); DbSupport dbSupport = getDbSupport(configuration, sqlHandler, schemaName); // Create connection DbUnitDatabaseConnection connection = new DbUnitDatabaseConnection(dataSource, dbSupport.getSchemaName()); DatabaseConfig config = connection.getConfig(); // Make sure that dbunit's correct IDataTypeFactory, that handles dbms specific data type issues, is used IDataTypeFactory dataTypeFactory = getInstanceOf(IDataTypeFactory.class, configuration, dbSupport.getDatabaseDialect()); config.setProperty(PROPERTY_DATATYPE_FACTORY, dataTypeFactory); // Make sure that table and column names are escaped using the dbms-specific identifier quote string if (dbSupport.getIdentifierQuoteString() != null) config.setProperty(PROPERTY_ESCAPE_PATTERN, dbSupport.getIdentifierQuoteString() + '?' + dbSupport.getIdentifierQuoteString()); // Make sure that batched statements are used to insert the data into the database config.setProperty(FEATURE_BATCHED_STATEMENTS, "true"); // Make sure that Oracle's recycled tables (BIN$) are ignored (value is used to ensure dbunit-2.2 compliancy) config.setProperty("http://www.dbunit.org/features/skipOracleRecycleBinTables", "true"); //注意这儿:根据不同的数据库(unitils的database.dialect配置参数)为dbunit //指定使用不同的IMetadataHandler实现(其它数据库都可以用默认的,还有一个Netezza也是特别的,这里忽略了) if("db2".equalsIgnoreCase(configuration.getProperty("database.dialect"))){ config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new Db2DataTypeFactory()); //由于dbunit自身提供的Db2MetadataHandler有BUG,所以这里使用自己写的 //MyDb2MetadataHandler,源码在后面了。 config.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MyDb2MetadataHandler()); }else if("mysql".equalsIgnoreCase(configuration.getProperty("database.dialect"))){ config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory()); config.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler()); } return connection; } }
下面是MyDb2MetadataHandler的源码:
package com.ridge.test.unitils.ext; import org.dbunit.ext.db2.Db2MetadataHandler; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import org.dbunit.util.SQLHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author : chenxh(quickselect@163.com) * @date: 13-10-9 */ public class MyDb2MetadataHandler extends Db2MetadataHandler { private static final Logger logger = LoggerFactory.getLogger(MyDb2MetadataHandler.class); public ResultSet getTables(DatabaseMetaData metaData, String schemaName, String[] tableType) throws SQLException { if(logger.isTraceEnabled()) logger.trace("tableExists(metaData={}, schemaName={}, tableType={}) - start", new Object[] {metaData, schemaName, tableType} ); return metaData.getTables(null, schemaName, "%", tableType); } public boolean tableExists(DatabaseMetaData metaData, String schema, String tableName) throws SQLException { ResultSet tableRs = metaData.getTables(null, schema, tableName, null); try { return tableRs.next(); } finally { SQLHelper.close(tableRs); } } public ResultSet getColumns(DatabaseMetaData databaseMetaData, String schemaName, String tableName) throws SQLException { // Note that MySQL uses the catalogName instead of the schemaName, so // pass in the given schema name as catalog name (first argument). ResultSet resultSet = databaseMetaData.getColumns( null, schemaName, tableName, "%"); return resultSet; } public boolean matches(ResultSet columnsResultSet, String catalog, String schema, String table, String column, boolean caseSensitive) throws SQLException { String catalogName = columnsResultSet.getString(1); String schemaName = columnsResultSet.getString(2); String tableName = columnsResultSet.getString(3); String columnName = columnsResultSet.getString(4); // MYSQL provides only a catalog but no schema if(schema != null && schemaName == null && catalog==null && catalogName != null){ logger.debug("Switching catalog/schema because the are mutually null"); schemaName = catalogName; catalogName = null; } boolean areEqual = areEqualIgnoreNull(table, tableName, caseSensitive) && areEqualIgnoreNull(column, columnName, caseSensitive); return areEqual; } private boolean areEqualIgnoreNull(String value1, String value2, boolean caseSensitive) { return SQLHelper.areEqualIgnoreNull(value1, value2, caseSensitive); } }
最后一步,更改unitils.properties的配置:
... unitils.module.dbunit.className=com.ridge.test.unitils.ext.MyDbunitModule ...
总结
采用前面的解决方案只能解决mysql的问题,且直接改dbunit的源码,是不好的方案,现在我把它废弃了,大家就不要了。
采用第二种方案吧,是优雅的解决方案,没有更改dbunit的源码,仅通过unitils的扩展配置实现了,所以你不要下载附件的dbunit-2.4.8.2.jar了,直接使用最新的dbunit版本吧:
<dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.4.9</version>> </exclusions> </dependency>
这个问题啊,让我死几回的心都有了,现在终于解决了,希望对大家有帮助!
- dbunit-2.4.8.2.jar (586.8 KB)
- 下载次数: 73
发表评论
-
几种常用的REST webservice客户端测试工具
2015-07-30 16:11 9587引言 开发了Rest WebService服务后,如果方便快捷 ... -
关于Idea testng单元测试乱码的解决
2013-07-02 10:50 14100问题 我是使用intel ... -
HyperSQL 2.0
2012-11-01 15:15 1917HyperSQL 2.0于本月7日发布了。此次发布距HSQLD ... -
Mockito
2012-06-07 16:40 7483Overview Packag ... -
追求代码质量: JUnit 4 与 TestNG 的对比
2012-05-05 15:35 2194经过长时间积极的开发之后,JUnit 4.0 于今年年初 ... -
探索 JUnit 4.4 新特性
2012-05-05 14:51 1733摘自:http://www.ibm.com 随着当前 ... -
单元测试系列之5:使用unitils测试Service层
2012-04-14 10:48 18324引述:Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
单元测试系列之4:使用Unitils测试DAO层
2012-04-12 16:32 19577Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
dbunit和poi版本不兼容的问题
2012-04-07 14:59 6902使用unitiles+dbunit 2.4.8,由于我的 ... -
单元测试系列之2:模拟利器Mockito
2012-03-30 11:38 15173引述:程序测试对 ... -
单元测试系列之1:开发测试的那些事儿
2012-03-28 12:52 9954引述:程序测试对保障应用程序正确性而言,其重要性怎 ...
相关推荐
DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类...
最新的最全的dbunit jar包以及入门教程
dbunit-2.4.9 源码 http://www.dbunit.org/apidocs/index.html 代码 API
DBUNIT使用的详细文档
dbunit的jar包,版本2.2
dbunit入门实例 dbunit入门实例 dbunit入门实例 dbunit入门实例
Junit,dbunit单元测试jar包
dbunit开发文档,供需要用dbunit进行开发的人使用
dbunit2.2完全包 数据库单元测试
dbunit-2.2.3..jar dbunit-2.4.2.jar dbunit-2.5.3.jar dbunit-2.7.0.jar 发现每个版本对JDK是有要求的,比如2.7 只能用于JDK1.8版本,所以整理好几个jar包挑选适合自己的
Dbunit 基本原理就是在跑测试用例运行之前对数据表做用户定义的操作,清空不想要的数据,插入用户自定义的数据,使得该数据表处于用户知道的一种状态。而用户自定义的数据使用项目里的一个 xml 文件来表示。 Xml ...
dbunit使用必需Jar包,总共4个必需Jar包
直接从http://www.dbunit.org/apidocs/index.html上下载的HTML文件的压缩包。 因为没有做成CHM,所以只要1分就行~
文档是关于DBUnit的ant的使用文档,通俗易懂
NULL 博文链接:https://coderdream.iteye.com/blog/2142973
DbUnit(http://dbunit.sourceforge.net/)则是专 门针对数据库测试的对JUnit的一个扩展, 它可以将测试对象数据库置于一个测试轮回之间的状态。 这个是主要jar包
一个很好的DBUnit的例子 博文链接:https://virgoooos.iteye.com/blog/186859
dbunit是一个基于junit扩展的数据库测试框架。 更多资源详见: http://blog.csdn.net/fanxiaobin577328725/article/details/51894331 (包含图书各部分和随书源码,还有其它资源的详细下载地址)
从http://www.dbunit.org/apidocs/index.html下载的HTML,然后自己制作的CHM,很辛苦,所以要2分吧~
通过DBUNIT做批量对比测试