IOperationListener

Overview

IOperationListener (org.dbunit, since 2.4.4) observes an IDatabaseConnection's lifecycle around an IDatabaseTester's onSetup()/ onTearDown() calls. Set one with IDatabaseTester.setOperationListener(). This page is the class-shape reference; see the IDatabaseTester guide for how the 3 hooks fit into the setup/teardown lifecycle in practice.

The 3 Hook Methods

Method Called
connectionRetrieved(IDatabaseConnection connection) Immediately after a connection is newly created or an existing one is retrieved, before the operation runs. Apply DatabaseConfig customizations here.
operationSetUpFinished(IDatabaseConnection connection) After the operation of IDatabaseTester.onSetup() completes, or fails - including when connectionRetrieved() itself threw.
operationTearDownFinished(IDatabaseConnection connection) After the operation of IDatabaseTester.onTearDown() completes, or fails - including when connectionRetrieved() itself threw.

Both *Finished methods exist so a listener can decide whether the connection should be closed at that point — the two built-in implementations below make opposite choices.

DefaultOperationListener

DefaultOperationListener is the default implementation used when none is explicitly set. Confirmed directly against its source: connectionRetrieved() is a no-op; both operationSetUpFinished() and operationTearDownFinished() close the connection. In other words, a fresh connection is created (or retrieved) for every single onSetup()/onTearDown() call unless a different listener is configured.

IOperationListener.NO_OP_OPERATION_LISTENER

IOperationListener.NO_OP_OPERATION_LISTENER is a static, trace-logging implementation that never closes the connection. Use it (or a custom non-closing listener) whenever a connection needs to survive past a single onSetup()/onTearDown() call — most commonly when pairing an IDatabaseTester with a CachingConnectionProvider, which would otherwise have its cached connection closed out from under it after the very first use:

databaseTester.setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);

Writing a Custom Listener

A custom listener isn’t limited to open/close decisions — since every hook receives the live IDatabaseConnection, it’s a convenient place for cross-cutting setup/teardown concerns such as logging or metrics:

IOperationListener listener = new IOperationListener()
{
    public void connectionRetrieved(IDatabaseConnection connection)
    {
        log.debug("Connection retrieved: {}", connection);
    }

    public void operationSetUpFinished(IDatabaseConnection connection)
    {
        log.debug("Setup finished for: {}", connection);
    }

    public void operationTearDownFinished(IDatabaseConnection connection)
    {
        log.debug("Teardown finished for: {}", connection);
    }
};
databaseTester.setOperationListener(listener);

Under the JUnit Jupiter Extension

DbUnitExtension on an annotation-driven test wraps the tester’s listener for the duration of one test, then puts the tester’s own listener back, so a tester shared across test methods carries nothing from one test to the next. Putting it back relies on the tester reporting its listener through getOperationListener(), as AbstractDatabaseTester and the testers built on it do. A custom IDatabaseTester that does not override it reports none, so there is nothing to put back and the extension’s wrapper stays installed.

  • A listener wrapped in a ConnectionPreservingOperationListener keeps that wrapper in force: the extension adds its own protection for the one connection it holds on top of it, and does not replace it.
  • A connection the extension resolves itself, rather than through the tester’s onSetup() or onTearDown(), is first offered to your listener’s connectionRetrieved(), so a DatabaseConfig customization made there, such as enabling the row count check, applies to it too. That includes the connection a plain @ExtendWith(DbUnitExtension.class) test resolves for the row count baseline and, on the setup/teardown path, a Connection or IDatabaseConnection test method parameter. The prep/expected path offers it to your listener’s connectionRetrieved() too, each time DefaultPrepAndExpectedTestCase runs a set up or tear down operation, but never to the *Finished callbacks: that class decides when its shared connection closes. The same connection can be offered more than once, by the extension and again when onSetup() retrieves it, and your listener sees one more retrieval than the 3.5.0 lifecycle gave it, so keep connectionRetrieved() idempotent, as configuring a DatabaseConfig is.