如何使用 Dbunit FlatXmlDataSet 填充 Oracle TIMESTAMP WITH ZONE 字段

How to populate an Oracle TIMESTAMP WITH ZONE field using Dbunit FlatXmlDataSet

我正在尝试通过填充 table 来为数据库单元测试设置数据,该 table 具有 TIMESTAMP(6) WITH TIME ZONE 类型的列,如下所示:

<timetable START_TIME="2015-03-01 10.00.00.000000000" END_TIME="2015-03-02 10.00.00.000000000"/>

但是当我 运行 测试时,我不断收到以下异常:

org.dbunit.dataset.NoSuchColumnException: TIMETABLE.START_TIME -  (Non-uppercase input column: START_TIME) 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.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
    at com.github.springtestdbunit.DbUnitRunner.setupOrTeardown(DbUnitRunner.java:194)
    at com.github.springtestdbunit.DbUnitRunner.beforeTestMethod(DbUnitRunner.java:66)
    at com.github.springtestdbunit.DbUnitTestExecutionListener.beforeTestMethod(DbUnitTestExecutionListener.java:185)
    at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:249)

我为时间戳字段尝试了不同的格式,包括添加时区后缀 +XX:XX 2015-03-01 10.00.00.000000000 +00.00 但无济于事。 我还尝试 运行 使用 VM 参数 -Duser.timezone=UTC 进行测试,但这也没有帮助。

有人知道如何实现吗?

编辑 1

我注意到控制台中出现以下警告:

2016-05-31 14:54:23 WARN  SQLHelper:429 - TIMETABLE.START_TIME data type (-101, 'TIMESTAMP(6) WITH TIME ZONE') not recognized and will be ignored. See FAQ for more information.
2016-05-31 14:54:23 WARN  SQLHelper:429 - TIMETABLE.END_TIME data type (-101, 'TIMESTAMP(6) WITH TIME ZONE') not recognized and will be ignored. See FAQ for more information.

所以看起来 Dbunit 不支持 TIMESTAMP WITH TIME ZONE 数据类型并忽略它,因此出现 NoSuchColumnException 异常

编辑 2

实际上 dbunit 已经通过 OracleDataTypeFactory class 支持 TIMESTAMP 数据类型。配置将如下所示:

<bean id="oracleDataTypeFactory" class="org.dbunit.ext.oracle.OracleDataTypeFactory"/>

<bean id="dbUnitDatabaseConfig" class="com.github.springtestdbunit.bean.DatabaseConfigBean">
        <property name="datatypeFactory" ref="oracleDataTypeFactory" />
</bean>

不幸的是,在这些配置更改之后,数据类型问题仍然存在,因为 dbunit DatabaseConfig.datatypeFactory 属性 被 DbUnitTestExecutionListener 重新设置为不支持的默认值 DefaultDataTypeFactory时间戳数据类型

我通过删除 Spring-dbunit 特定注释(@TestExecutionListeners@DbUnitConfiguration)设法加载了 TIMESTAMP 数据。我仍然不得不使用 @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)。然后我使用 'old' Dbunit 方法来设置和拆卸数据并检查数据预期。这不像 Spring-dbunit 注释 @DatabaseSetup@DatabaseTearDown@ExpectedDatabase 那样简洁,但它确实有效(参见下面的代码片段)。我还在我的测试上下文中保留了 OracleDataTypeFactory;这对于 Dbunit 识别 TIMESTAMP 数据类型至关重要。

我认为我遇到的问题可能是 spring-dbunit 测试执行侦听器中的错误的表现。我特别怀疑DbUnitTestExecutionListener

设置:

@Before
    public void setUp() throws SQLException, IOException, DataSetException, DatabaseUnitException {    
        Resource resource = new ClassPathResource("path/to/data_setup.xml");
        FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
        builder.setColumnSensing(true);
        FlatXmlDataSet dataSetup = builder.build(resource.getInputStream());
        DatabaseOperation.CLEAN_INSERT.execute(dbUnitDatabaseConnection, dataSetup);    
    }

拆解:

@After
    public void tearDown() throws SQLException, IOException, DataSetException, DatabaseUnitException {
        Resource resource = new ClassPathResource("path/to/data_teardown.xml");
        FlatXmlDataSet dataTearDown = new FlatXmlDataSetBuilder().build(resource.getInputStream());
        DatabaseOperation.DELETE_ALL.execute(dbUnitDatabaseConnection, dataTearDown);
    }

期望值(在测试方法内):

QueryDataSet actualDataSet = new QueryDataSet(dbUnitDatabaseConnection);
actualDataSet.addTable("YOUR_TABLE", "<YOUR_SQL_QUERY>");
FlatXmlDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(new ClassPathResource("path/to/data_expectation.xml").getInputStream());
Assertion.assertEquals(expectedDataSet, actualDataSet);