我正在为数据库组件编写一些单元测试.为此,我使用专用的测试数据库(Postgresql,与生产数据库相同)和dbUnit.
现在我想创建整个测试数据库的XML转储.我目前使用的是FAQ page of dbUnit的代码
IDatabaseConnection connection = new DatabaseConnection(conn);
connection.getConfig().setProperty("http://www.dbunit.org/properties/datatypeFactory", new PostgresqlDataTypeFactory());
IDataSet fullDataSet = connection.createDataSet();
FlatXmlDataSet.write(fullDataSet, new FileOutputStream("full.xml"));
这一切都很有效,除了Array类型的列.dbUnit只是将它们排除在外.我希望通过添加PostgresqlDataTypeFactory来修复它,但这并没有改变一件事.
有人知道如何在dbUnit中添加对postgresql数组的支持吗?
解决方法:
我在github上找到了这个项目:https://github.com/JarnTang/dbunit-ext
我正在使用其ArrayDataType类进行小修改:
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.datatype.AbstractDataType;
import org.dbunit.dataset.datatype.TypeCastException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.lang.invoke.MethodHandles;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class ArrayDataType extends AbstractDataType {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final Class CLASS_TYPE = Array.class;
public ArrayDataType(String name, int sqlType, boolean isNumber) {
super(name, sqlType, CLASS_TYPE, isNumber);
}
@Override
public Object typeCast(Object value) throws TypeCastException {
if (value == null || value == ITable.NO_VALUE) {
return null;
}
if (value instanceof String) {
return new String[]{(String) value};
}
if (value instanceof String[]) {
return value;
}
if (value instanceof Date ||
value instanceof Time ||
value instanceof Timestamp) {
return new String[]{value.toString()};
}
if (value instanceof Boolean) {
return new String[]{value.toString()};
}
if (value instanceof Number) {
try {
return new String[]{value.toString()};
} catch (NumberFormatException e) {
throw new TypeCastException(value, this, e);
}
}
if (value instanceof Array) {
try {
Array a = (Array) value;
return a.getArray();
} catch (Exception e) {
e.printStackTrace();
}
}
if (value instanceof Blob) {
try {
Blob blob = (Blob) value;
byte[] blobValue = blob.getBytes(1, (int) blob.length());
return typeCast(blobValue);
} catch (SQLException e) {
throw new TypeCastException(value, this, e);
}
}
if (value instanceof Clob) {
try {
Clob clobValue = (Clob) value;
int length = (int) clobValue.length();
if (length > 0) {
return clobValue.getSubString(1, length);
}
return "";
} catch (SQLException e) {
throw new TypeCastException(value, this, e);
}
}
log.warn("Unknown/unsupported object type '{}' - " +
"will invoke toString() as last fallback which " +
"might produce undesired results",
value.getClass().getName());
return value.toString();
}
@Override
public Object getSqlValue(int column, ResultSet resultSet)
throws SQLException, TypeCastException {
if (log.isDebugEnabled())
log.debug("getSqlValue(column={}, resultSet={}) - start", column, resultSet);
String value = resultSet.getString(column);
if (value == null || resultSet.wasNull()) {
return null;
}
return value;
}
@Override
public void setSqlValue(Object value, int column, PreparedStatement statement)
throws SQLException, TypeCastException {
if (log.isDebugEnabled())
log.debug("setSqlValue(value={}, column={}, statement={}) - start",
value, column, statement);
Array array = isNumber() ? statement.getConnection().createArrayOf("integer", toArray(value)) :
statement.getConnection().createArrayOf("text", toArray(value));
statement.setObject(column, array);
}
private Object[] toArray(Object value) {
List list = new ArrayList(0);
if (value instanceof String) {
String valueStr = (String) value;
if (!StringUtils.isEmpty(valueStr)) {
valueStr = valueStr.replaceAll("[{}]", "");
return valueStr.split(",");
}
}
return list.toArray();
}
}
然后你需要扩展PostgresqlDataTypeFactory,例如:
import org.dbunit.dataset.datatype.DataType;
import org.dbunit.dataset.datatype.DataTypeException;
import org.dbunit.ext.postgresql.PostgresqlDataTypeFactory;
public class CustomPostgresqlDataTypeFactory extends PostgresqlDataTypeFactory{
@Override
public DataType createDataType(int sqlType, String sqlTypeName, String tableName, String columnName) throws DataTypeException {
if (sqlType == 2003) {
if (sqlTypeName.equals("_text"))
return new ArrayDataType(sqlTypeName, sqlType, false);
if (sqlTypeName.contains("int"))
return new ArrayDataType(sqlTypeName, sqlType, true);
throw new UnsupportedSqlTypeException("Unsupported sql type: " + sqlTypeName);
}
return super.createDataType(sqlType, sqlTypeName, tableName, columnName);
}
}
并将CustomPostgresqlDataTypeFactory设置为IDatabaseConnection:
IDatabaseConnection conn = databaseTester.getConnection();
conn.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
new CustomPostgresqlDataTypeFactory());