Class DbUnitExtension
- All Implemented Interfaces:
org.junit.jupiter.api.extension.AfterTestExecutionCallback,org.junit.jupiter.api.extension.BeforeTestExecutionCallback,org.junit.jupiter.api.extension.Extension,org.junit.jupiter.api.extension.ParameterResolver,org.junit.jupiter.api.extension.TestInstantiationAwareExtension
org.dbunit.annotation family: DbUnitPrep, DbUnitSetup,
DbUnitExpected, DbUnitTearDown, and DbUnitConfig. Add
@DbUnitTest (or @ExtendWith(DbUnitExtension.class) directly) to
opt a test class in.
The two paths
Without DbUnitExpected, this is the setup/teardown path: the
DbUnitPrep dataset (if any) and DbUnitSetup operation are applied, then
IDatabaseTester.onSetup() runs before the test method and
IDatabaseTester.onTearDown() after it. The test method asserts results however it
likes.
With DbUnitExpected present, the test switches onto the
PrepAndExpectedTestCase prep/expected path: configureTest() and
preTest() run before the test method, postTest() after it - postTest()
compares the database against the DbUnitExpected dataset, so the verifying is done
for you, skipping it when the test method itself already failed so a verification failure
never masks the real cause. Neither path is a reduced form of the other; they run different
lifecycles.
@DbUnitTest
class AccountRepositoryTest {
IDatabaseTester databaseTester;
AccountRepositoryTest() throws ClassNotFoundException {
databaseTester = new JdbcDatabaseTester("driver", "url", "user", "pass");
}
@Test
@DbUnitPrep("accounts-prep.xml")
@DbUnitExpected(value = "accounts-expected.xml", verifyTables = {"ACCOUNT"})
void testWithdraw_sufficientBalance_decrementsBalance() { ... }
}
Resolving the tester or test case
First match wins:
- A field annotated
DbUnitTestCase, whose type implementsPrepAndExpectedTestCase- that instance is driven directly. - A field annotated
DbUnitTester, whose type implementsIDatabaseTester. DbUnitConfig.databaseTesterFactory(), reflectively instantiated and asked to create a tester.- The original (3.5.0) auto-scan: exactly one non-static field assignable to
IDatabaseTester, nearest declaring class wins - unchanged, so every 3.5.0 test keeps working untouched.
Field discovery walks every test instance in scope, innermost first, so a @Nested
test class inherits its enclosing class's tester field.
Programmatic setup
Without annotations, configure the tester - including its dataset - in a
@BeforeEach method; those run before this extension's setup callback:
@ExtendWith(DbUnitExtension.class)
class MyDatabaseTest {
IDatabaseTester databaseTester;
MyDatabaseTest() throws ClassNotFoundException {
databaseTester = new JdbcDatabaseTester("driver", "url", "user", "pass");
}
@BeforeEach
void loadDataset() throws Exception {
databaseTester.setDataSet(new FlatXmlDataSetBuilder().build(...));
}
@Test
void testSomething() { ... }
}
This zero-annotation style is the 3.5.0 lifecycle: the extension calls only
onSetup()/onTearDown() on the tester and runs the row count check around
them, without replacing the tester's IOperationListener. The connection it
resolves for the row count baseline is never closed before onSetup() - a tester that
returns one fixed connection from every call (e.g. a DefaultDatabaseTester built from
a fixed connection) would otherwise run onSetup() against a closed one - and is
closed after the test when closeConnectionAfterTest allows and the tester's listener
is not NO_OP. Adding any @DbUnit* annotation or a
@DbUnitTester/@DbUnitTestCase field opts the test
into the fuller annotation-driven lifecycle described above.
Parameter injection
Also a ParameterResolver for IDatabaseTester, PrepAndExpectedTestCase,
IDatabaseConnection, and Connection parameters on @Test and
@BeforeEach methods - but only for a test that opts into the
org.dbunit.annotation family: one carrying @DbUnitTest or any
@DbUnit* annotation (DbUnitConfig, DbUnitPrep, DbUnitSetup,
DbUnitExpected, DbUnitTearDown, DbUnitRowCountCheck) on the class or
method, or a @DbUnitTester/@DbUnitTestCase field.
A bare @ExtendWith(DbUnitExtension.class) class with only a plain, unannotated
IDatabaseTester field keeps the 3.5.0 lifecycle behaviour untouched and has no
parameter claimed here, so another extension resolving a Connection (or any of the
other three types) on the same test stays unambiguous. Switch such a class to
@DbUnitTest, or mark its field @DbUnitTester, to opt
its parameters in.
On an annotation-driven test this extension claims every
Connection parameter on a @Test/@BeforeEach method. Another
extension on the same test that also resolves java.sql.Connection - Spring's
SpringExtension, Testcontainers, a JPA harness - then collides with JUnit's
"discovered multiple competing ParameterResolvers". Set
@DbUnitConfig(injectConnectionParameter = false)
to yield the bare Connection to that extension; the dbUnit-specific
IDatabaseConnection parameter is still resolved (no other framework claims that
type) - inject it and call getConnection().
The injected IDatabaseConnection/Connection is managed for the test's
duration and closed afterward - by this extension on the setup/teardown path, by the
driven PrepAndExpectedTestCase on the prep/expected path; do not close it
yourself. A @BeforeEach parameter resolves
before beforeTestExecution(ExtensionContext) runs - JUnit Jupiter always calls
@BeforeEach methods first - so it sees the tester/connection exactly as they exist
before this extension's own setup: DbUnitPrep's dataset, if any, is not loaded onto
it yet.
Not safe for concurrent execution of test methods that resolve to the same tester or test
case instance - e.g. a static @DbUnitTester/
@DbUnitTestCase field, or any instance field at all under
@TestInstance(Lifecycle.PER_CLASS) - since this extension applies annotations and
drives the dbUnit lifecycle against it without synchronization. Run such test methods
sequentially (JUnit Jupiter's own default) rather than under
junit.jupiter.execution.parallel.enabled=true, or give each test method's own tester
its own non-shared field.
- Since:
- 3.5.0
- Author:
- Jeff Jensen
- See Also:
-
Nested Class Summary
Nested classes/interfaces inherited from interface org.junit.jupiter.api.extension.TestInstantiationAwareExtension
org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidafterTestExecution(org.junit.jupiter.api.extension.ExtensionContext context) Runs the storedAnnotatedTestExecutor's after-test steps.voidbeforeTestExecution(org.junit.jupiter.api.extension.ExtensionContext context) Resolves the configuredAnnotatedTestExecutor- reusing one already resolved for this test by parameter injection into a@BeforeEachmethod, if any - and runs its before-test steps.resolveParameter(org.junit.jupiter.api.extension.ParameterContext parameterContext, org.junit.jupiter.api.extension.ExtensionContext extensionContext) Resolves a parameter from the sameAnnotatedTestExecutorthatbeforeTestExecution(ExtensionContext)drives - reusing it (creating and caching it on first use, for a@BeforeEachparameter resolved beforebeforeTestExecutionruns) rather than resolving a second tester or test case independently.booleansupportsParameter(org.junit.jupiter.api.extension.ParameterContext parameterContext, org.junit.jupiter.api.extension.ExtensionContext extensionContext) Reports whether this extension resolves the given parameter: anIDatabaseTester,PrepAndExpectedTestCase,IDatabaseConnection, orConnectionparameter, declared on the current test method or a@BeforeEachmethod - the only two contextsafterTestExecution(ExtensionContext)still runs after, so a connection this executor resolves is guaranteed to still be open, and eventually closed, for the parameter's entire lifetime.Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface org.junit.jupiter.api.extension.TestInstantiationAwareExtension
getTestInstantiationExtensionContextScope
-
Constructor Details
-
DbUnitExtension
public DbUnitExtension()Creates the extension.
-
-
Method Details
-
beforeTestExecution
public void beforeTestExecution(org.junit.jupiter.api.extension.ExtensionContext context) throws Exception Resolves the configuredAnnotatedTestExecutor- reusing one already resolved for this test by parameter injection into a@BeforeEachmethod, if any - and runs its before-test steps.- Specified by:
beforeTestExecutionin interfaceorg.junit.jupiter.api.extension.BeforeTestExecutionCallback- Parameters:
context- The extension context for the test method.- Throws:
Exception- If resolving the tester or test case, or running the before-test steps, fails.
-
afterTestExecution
public void afterTestExecution(org.junit.jupiter.api.extension.ExtensionContext context) throws Exception Runs the storedAnnotatedTestExecutor's after-test steps.A failure here is simply left to propagate rather than caught and reconciled by hand: the JUnit Platform engine invokes every
AfterTestExecutionCallbackthrough the sameThrowableCollectorthat already collected the test method's own outcome (if any), so the engine itself already applies the correct precedence - a genuine failure here is promoted over a mere test abort from the test method (e.g. a failedAssumptions.assumeTrue()), with the abort attached as a suppressed exception on the promoted failure instead of the failure being silently swallowed into the discarded abort; against a real test method failure, this failure is the one attached as suppressed, so JUnit still reports the original failure as the cause. Reimplementing that precedence here would only risk getting it wrong.- Specified by:
afterTestExecutionin interfaceorg.junit.jupiter.api.extension.AfterTestExecutionCallback- Parameters:
context- The extension context for the test method.- Throws:
Exception- If the after-test steps fail.
-
supportsParameter
public boolean supportsParameter(org.junit.jupiter.api.extension.ParameterContext parameterContext, org.junit.jupiter.api.extension.ExtensionContext extensionContext) throws org.junit.jupiter.api.extension.ParameterResolutionException Reports whether this extension resolves the given parameter: anIDatabaseTester,PrepAndExpectedTestCase,IDatabaseConnection, orConnectionparameter, declared on the current test method or a@BeforeEachmethod - the only two contextsafterTestExecution(ExtensionContext)still runs after, so a connection this executor resolves is guaranteed to still be open, and eventually closed, for the parameter's entire lifetime. A matching parameter on any other method (constructor,@BeforeAll,@AfterEach,@AfterAll) is declined here rather than handed out already-closed - or, worse, opened for the first time with nothing left to ever close it - since@AfterEachand@AfterAllrun afterafterTestExecution(ExtensionContext)already has.Also declined - regardless of type or method - unless the test opts into the
org.dbunit.annotationfamily (seeisAnnotationDriven(ExtensionContext)). A bare@ExtendWith(DbUnitExtension.class)class with only a plain, unannotatedIDatabaseTesterfield is the 3.5.0 lifecycle-only style: it never claimed a parameter before this method existed, and does not now, so another extension resolving one of these types -Connectionespecially - on the same test is not left competing with an unconditional claim here. An annotation-driven test can still opt its bareConnectionparameter back out with@DbUnitConfig(injectConnectionParameter = false)while keeping the other three types.- Specified by:
supportsParameterin interfaceorg.junit.jupiter.api.extension.ParameterResolver- Parameters:
parameterContext- The parameter to resolve.extensionContext- The extension context for the test method.- Returns:
truefor a matching parameter type on the test method or a@BeforeEachmethod of an annotation-driven test.- Throws:
org.junit.jupiter.api.extension.ParameterResolutionException- Never thrown directly; declared by theParameterResolvercontract.
-
resolveParameter
public Object resolveParameter(org.junit.jupiter.api.extension.ParameterContext parameterContext, org.junit.jupiter.api.extension.ExtensionContext extensionContext) throws org.junit.jupiter.api.extension.ParameterResolutionException Resolves a parameter from the sameAnnotatedTestExecutorthatbeforeTestExecution(ExtensionContext)drives - reusing it (creating and caching it on first use, for a@BeforeEachparameter resolved beforebeforeTestExecutionruns) rather than resolving a second tester or test case independently.A
PrepAndExpectedTestCaseparameter requires a@DbUnitTestCasefield: without one, the executor may not have constructed its own instance yet - seeAnnotatedTestExecutor.getPrepAndExpectedTestCase()- so there is no single instance to inject.- Specified by:
resolveParameterin interfaceorg.junit.jupiter.api.extension.ParameterResolver- Parameters:
parameterContext- The parameter to resolve.extensionContext- The extension context for the test method.- Returns:
- The resolved
IDatabaseTester,PrepAndExpectedTestCase,IDatabaseConnection, orConnectionvalue. - Throws:
org.junit.jupiter.api.extension.ParameterResolutionException- If no test instance exists yet, or if resolution otherwise fails. The first is not reachable through JUnit Jupiter's own engine for a parameter this class actually claims - a static-scope context such as@BeforeAllis already declined bysupportsParameter(ParameterContext, ExtensionContext), so the engine never calls this method for it at all - only a caller invoking this method directly, without checking that first, could still hit it.
-