首先,要扩展DBUnit支持的数据类型,我们必须知道,自己要扩展的数据类型的一些工作情况:
a)驱动程序为该列返回什么JDBC类型;
b)驱动程序为这些对象返回什么Java类;
要解答上面的问题,我们可以用下面的方法来进行测试:
Public class PrintMetaData{ public static void main(String[] args) throws SQLException { String sql = “select * from tableName order by 1”; Connnection conn = DataSourceUtils.getDataSource().getConnection(); ResultSet rs = conn.createStatement().executeQuery(sql); ResultSetMetaData metaData = rs.getMetaData(); System.out.println(“metaData.getColumnType”+metaData.getColumnType(列号,计数从1开始)); while(rs.next()) { Object o = rs.getObject(1); System.out.println(“c.getClass() = ” + c.getClass()); System.out.println(“c.toString() = ” + c.toString()); } } }
通过这样的方式我们可以清楚的知道自己需要扩展的类型,在驱动里的表现形式。有了这样的基础我们就可以开始扩展我们想要的数据类型了。(以下的内容我们以扩展一个Oracle里面的特殊字段类型TimeStamp with time zone为例)
首先我们需要为我们要扩展的类型定义出自己的OracleTimeStampTZDataType类,该类的实现如下:
import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Date; import oracle.jdbc.OracleTypes; import oracle.sql.TIMESTAMP; import org.dbunit.dataset.datatype.AbstractDataType; import org.dbunit.dataset.datatype.TypeCastException; public class OracleTimeStampTZDataType extends AbstractDataType { private static final String DATE_FORMATE = "yyyy-MM-dd hh:mm:ss"; public OracleTimeStampTZDataType() { super("TIMESTAMPTZ", OracleTypes.TIMESTAMP, TIMESTAMP.class, false); } @Override public Object typeCast(Object value) throws TypeCastException { SimpleDateFormat formate = new SimpleDateFormat(DATE_FORMATE); Timestamp stamp =null; try { Date date = formate.parse((String)value); stamp = new Timestamp(date.getTime()); } catch(Exception ex) { ex.printStackTrace(); } return stamp; } public int compare(Object o1, Object o2) throws TypeCastException { return o1.toString().equals(o2.toString()) ? 0 : 1; } }
定义完我们自己的数据类型后,我们还需要为自定义类型实现一个创建这个自定义对象的类型的工厂类,该类需要继承DBUnit中的DefaultDataTypeFactory类,具体实现如下:
import java.sql.Types; import org.dbunit.dataset.datatype.BinaryStreamDataType; import org.dbunit.dataset.datatype.DataType; import org.dbunit.dataset.datatype.DataTypeException; import org.dbunit.dataset.datatype.DefaultDataTypeFactory; import org.dbunit.ext.oracle.OracleBlobDataType; import org.dbunit.ext.oracle.OracleClobDataType; import org.dbunit.ext.oracle.OracleNClobDataType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OracleTimeStampTZDataTypeFactory extends DefaultDataTypeFactory { /** * Logger for this class */ private static final Logger logger = LoggerFactory.getLogger(OracleTimeStampTZDataTypeFactory.class); public static final DataType ORACLE_BLOB = new OracleBlobDataType(); public static final DataType ORACLE_CLOB = new OracleClobDataType(); public static final DataType ORACLE_NCLOB = new OracleNClobDataType(); public static final DataType LONG_RAW = new BinaryStreamDataType( "LONG RAW", Types.LONGVARBINARY); public static final DataType ORACLE_TIMESTAMPTZ = new OracleTimeStampTZDataType(); public DataType createDataType(int sqlType, String sqlTypeName) throws DataTypeException { logger.debug("createDataType(sqlType=" + sqlType + ", sqlTypeName=" + sqlTypeName + ") - start"); // Map Oracle DATE to TIMESTAMP if (sqlType == Types.DATE) { return DataType.TIMESTAMP; } // TIMESTAMOTZ if(sqlTypeName.startsWith("TIMESTAMP(6) WITH TIME ZONE")) { return ORACLE_TIMESTAMPTZ; } // TIMESTAMP if (sqlTypeName.startsWith("TIMESTAMP")) { return DataType.TIMESTAMP; } // BLOB if ("BLOB".equals(sqlTypeName)) { return ORACLE_BLOB; } // CLOB if ("CLOB".equals(sqlTypeName)) { return ORACLE_CLOB; } // NCLOB if ("NCLOB".equals(sqlTypeName)) { return ORACLE_NCLOB; } // NVARCHAR2 if ("NVARCHAR2".equals(sqlTypeName)) { return DataType.VARCHAR; } // NCHAR if (sqlTypeName.startsWith("NCHAR")) { return DataType.CHAR; } // FLOAT if ("FLOAT".equals(sqlTypeName)) { return DataType.FLOAT; } // LONG RAW if (LONG_RAW.toString().equals(sqlTypeName)) { return LONG_RAW; } return super.createDataType(sqlType, sqlTypeName); } }
至此我们已经完成了自定义类型的相关定义,但是要让DBUnit支持我们的自定义类型,我们还需要实现一个针对我们自定义类型的数据库连接对象OracleTZConnection,同样该类需要继承DBUnit的DatabaseConnection类,具体的实现如下:
import java.sql.Connection; import org.dbunit.database.DatabaseConfig; import org.dbunit.database.DatabaseConnection; public class OracleTZConnection extends DatabaseConnection{ public OracleTZConnection(Connection connection, String schema) { super(connection, schema != null ? schema.toUpperCase() : null); getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new OracleTimeStampTZDataTypeFactory()); } }
OK,完成上面这些定义之后,我们已经完成了一个自定义类型在DBUnit中的扩展。最后给出一个使用该自定义类型做DBUnit测试的小的demo代码:
import org.dbunit.DBTestCase; import org.dbunit.database.IDatabaseConnection; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.FlatXmlDataSet; import org.dbunit.operation.DatabaseOperation; import org.junit.Before; import delete.Test; public class MyTest extends DBTestCase{ @Override protected IDataSet getDataSet() throws Exception { return new FlatXmlDataSet(this.getClass().getResourceAsStream("MyTest.xml")); } @Override protected IDatabaseConnection getConnection() throws Exception { return new OracleTZConnection(Test.getConnection(), "ZK"); } @Before public void setUp() throws Exception { DatabaseOperation.INSERT.execute(getConnection(), getDataSet()); } public void testTT() {} }