IDatabaseTester

Overview

IDatabaseTester adds dbUnit’s setup/teardown lifecycle to a test class by composition — a test class holds an IDatabaseTester field (constructed directly or dependency-injected) instead of extending DBTestCase.

This is the preferred style. Reach for it over a DBTestCase subclass when:

  • Your test class already extends something else — Java allows only one superclass, and a forced DBTestCase base class competes with any other base class your test infrastructure needs.
  • You use dependency injection (e.g. Spring) and want the database tester wired in like any other collaborator, rather than configured through inherited setter calls.
  • You want the setup/teardown mechanics visible and testable as an object, not implicit behavior inherited from a base class.

DBTestCase and its subclasses remain fully supported for tests that prefer inheritance — see Test Integration for both styles side by side, and Migrating to IDatabaseTester for converting existing DBTestCase subclasses.

Interface Hierarchy

IDatabaseTester is the interface; AbstractDatabaseTester implements its setup/teardown/listener plumbing and leaves only getConnection() to each concrete subclass:

Implementation How it obtains a connection
DefaultDatabaseTester Wraps an already-constructed IDatabaseConnection, or (since 3.4.0) a Callable<IDatabaseConnection> factory paired with a CachingConnectionProvider.
JdbcDatabaseTester Opens connections via DriverManager, given a driver class name and JDBC URL (plus optional username/password/schema).
PropertiesBasedJdbcDatabaseTester A JdbcDatabaseTester that reads its driver class, URL, username, password, and schema from System properties (dbunit.driverClass, dbunit.connectionUrl, dbunit.username, dbunit.password, dbunit.schema) instead of constructor arguments.
DataSourceDatabaseTester Pulls connections from a javax.sql.DataSource — the natural fit when a DI container already manages a pooled DataSource.
JndiDatabaseTester Looks up a javax.sql.DataSource from a JNDI context by name, then behaves like DataSourceDatabaseTester.

Lifecycle

  1. setDataSet(IDataSet) — sets the dataset the setup/teardown operations act on.
  2. onSetup() — call at the start of a test (e.g. @BeforeEach). Executes getSetUpOperation() (default CLEAN_INSERT) against the dataset.
  3. onTearDown() — call at the end of a test (e.g. @AfterEach). Executes getTearDownOperation() (default NONE — teardown is opt-in; set it explicitly, e.g. to DELETE_ALL, if you want automatic cleanup).
  4. setSetUpOperation(DatabaseOperation) / setTearDownOperation(DatabaseOperation) — override either default. See Database Operations for the full set.
private final IDatabaseTester databaseTester =
        new JdbcDatabaseTester("org.h2.Driver", "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1");

@BeforeEach
void setUp() throws Exception
{
    databaseTester.setDataSet(new FlatXmlDataSetBuilder().build(new File("prep.xml")));
    databaseTester.setTearDownOperation(DatabaseOperation.DELETE_ALL);
    databaseTester.onSetup();
}

@AfterEach
void tearDown() throws Exception
{
    databaseTester.onTearDown();
}

IOperationListener Hooks

IOperationListener observes connection handling around onSetup()/onTearDown(). Set one with setOperationListener():

  • connectionRetrieved(IDatabaseConnection) — called right after a connection is created or retrieved, before the operation runs. Apply per-connection DatabaseConfig customizations here (data type factory, feature flags, etc.).
  • operationSetUpFinished(IDatabaseConnection) — called after `onSetup()’s operation completes.
  • operationTearDownFinished(IDatabaseConnection) — called after `onTearDown()’s operation completes.

The default listener (DefaultOperationListener) closes the connection in both *Finished callbacks — a fresh connection every onSetup()/ onTearDown() call. Set IOperationListener.NO_OP_OPERATION_LISTENER (or a custom non-closing listener) when a connection needs to survive past one call — most commonly when pairing with a CachingConnectionProvider, below.

Pairing With CachingConnectionProvider

org.dbunit.database.CachingConnectionProvider (new in 3.4.0) caches one IDatabaseConnection and reuses it across many getConnection() calls instead of opening a new one every time, transparently replacing it if it goes stale or is closed. Every IDatabaseTester implementation above accepts one via an additive constructor overload. Pair it with NO_OP_OPERATION_LISTENER — otherwise the default listener closes the connection the provider is trying to reuse:

private static final CachingConnectionProvider CONNECTION_PROVIDER =
        new CachingConnectionProvider();

private IDatabaseTester databaseTester;

@BeforeEach
void setUp() throws Exception
{
    databaseTester = new JdbcDatabaseTester("org.h2.Driver",
            "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1", null, null, null,
            CONNECTION_PROVIDER);
    databaseTester.setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
    databaseTester.setDataSet(myDataSet);
    databaseTester.setTearDownOperation(DatabaseOperation.DELETE_ALL);
    databaseTester.onSetup();
}

Share one CachingConnectionProvider instance across every test method that should reuse the connection — typically a static field on a common test base class. See Connections & Configuration for how CachingConnectionProvider fits alongside IDatabaseConnection, and Best Practices for when connection reuse across test methods is (and isn’t) a good idea.

Complete Example

class AccountRepositoryTest
{
    private static final String DBUNIT_DATA_DIR = "/dbunit/account/";

    private final IDatabaseTester databaseTester =
            new JdbcDatabaseTester("org.h2.Driver",
                    "jdbc:h2:mem:accountRepositoryTest;DB_CLOSE_DELAY=-1");

    @BeforeEach
    void setUp() throws Exception
    {
        final IDataSet prepDataSet = new FlatXmlDataSetBuilder()
                .build(getClass().getResourceAsStream(DBUNIT_DATA_DIR + "account-prep.xml"));

        databaseTester.setDataSet(prepDataSet);
        databaseTester.setTearDownOperation(DatabaseOperation.DELETE_ALL);
        databaseTester.onSetup();
    }

    @AfterEach
    void tearDown() throws Exception
    {
        databaseTester.onTearDown();
    }

    @Test
    void testWithdraw_sufficientBalance_decrementsBalance() throws Exception
    {
        final AccountRepository repository =
                new AccountRepository(databaseTester.getConnection().getConnection());

        repository.withdraw(1L, 50);

        final IDataSet expectedDataSet = new FlatXmlDataSetBuilder()
                .build(getClass().getResourceAsStream(DBUNIT_DATA_DIR + "account-expected.xml"));
        final ITable expectedTable = expectedDataSet.getTable("account");
        final ITable actualTable = databaseTester.getConnection()
                .createDataSet(new String[] { "account" }).getTable("account");

        Assertion.assertEquals(expectedTable, actualTable);
    }
}