javah2spring-testdbunitteardown

Exception during teardown in a Transactional DbUnit test


Test class declaration

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestH2Config.class })
@TestExecutionListeners({
        DependencyInjectionTestExecutionListener.class,
        DbUnitTestExecutionListener.class,
        TransactionalTestExecutionListener.class
})
@TransactionConfiguration(defaultRollback = true)
@Transactional
public class BookServiceIT {
    // ... dependencies injection goes here (omitted for brevity)
    @Test
    @DatabaseSetup("/datasets/import.xml")
    public void testCase1() throws Exception {
        // .. create Book in Organization(id=2)
        // ... read and create data in database (omitted for brevity)
    }
}

test/resources/datasets/import.xml

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
  <Organization id="2" name="Gov. Library" inactive="false" />
</dataset>

Maven command that is used to run tests:

mvn verify -T 1C

I'm attaching an exception stack trace (test fails only in Codeship Linux environment):

WARNING: Caught exception while allowing TestExecutionListener [com.github.springtestdbunit.TransactionDbUnitTestExecutionListener@3f191a96] to process 'before' execution of test method [public void com.test.integration.BookServiceIT.testCase1() throws java.lang.Exception] for test instance [com.test.integration.BookServiceIT@15f18e5] org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK_JNCMPQJWFCJEXX62EA1P06VLP: ITEST.BOOK FOREIGN KEY(LIBRARY_ID) REFERENCES ITEST.ORGANIZATION(ID) (2)"; SQL statement:delete from ORGANIZATION [23503-195]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
        at org.h2.message.DbException.get(DbException.java:179)
        at org.h2.message.DbException.get(DbException.java:155)
        at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:425)
        at org.h2.constraint.ConstraintReferential.checkRowRefTable(ConstraintReferential.java:442)
        at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:317)
        at org.h2.table.Table.fireConstraints(Table.java:976)
        at org.h2.table.Table.fireAfterRow(Table.java:994)
        at org.h2.command.dml.Delete.update(Delete.java:101)
        at org.h2.command.CommandContainer.update(CommandContainer.java:101)
        at org.h2.command.Command.executeUpdate(Command.java:260)
        at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:193)
        at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:165)
        at org.apache.commons.dbcp.DelegatingStatement.execute(DelegatingStatement.java:264)
        at org.apache.commons.dbcp.DelegatingStatement.execute(DelegatingStatement.java:264)
        at org.dbunit.database.statement.SimpleStatement.executeBatch(SimpleStatement.java:69)
        at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:126)
        at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
        at com.github.springtestdbunit.DbUnitRunner.setupOrTeardown(DbUnitRunner.java:162)
        at com.github.springtestdbunit.DbUnitRunner.beforeTestMethod(DbUnitRunner.java:60)
        at com.github.springtestdbunit.DbUnitTestExecutionListener.beforeTestMethod(DbUnitTestExecutionListener.java:160)
        at com.github.springtestdbunit.TestExecutionListenerChain$3.call(TestExecutionListenerChain.java:93)
        at com.github.springtestdbunit.TestExecutionListenerChain.runChain(TestExecutionListenerChain.java:126)
        at com.github.springtestdbunit.TestExecutionListenerChain.forwards(TestExecutionListenerChain.java:115)
        at com.github.springtestdbunit.TestExecutionListenerChain.beforeTestMethod(TestExecutionListenerChain.java:91)
        at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:249)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:70)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
        at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)

I've tried to use other execution listeners (that I've found in DbUnit documentation), but I've got the same exception...

@TestExecutionListeners({
        DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class,
        TransactionDbUnitTestExecutionListener.class
})

UPD.: I've tried to add an explicit teardown: deleted the Book in the end of testCase() method. But the exception still persists.


Solution

  • dbUnit deletes the rows in the reverse order of the data listed in the dataset files. Ensure the files have the rows with foreign keys placed after the ones with the primary keys/one side of the relationship.

    Update: A book table row exists from the test, so tell dbUnit to delete it too. One way is to add an empty table for the foreign key table to the dataset file after the primary table:

    <book/>
    

    So the dbUnit teardown operation sees that table and cleans it up too.