Class MultiDataSourcePrepAndExpectedTestCase
IDatabaseConnections
around one run of the code under test, by fanning the PrepAndExpectedTestCase lifecycle
out to one delegate per data source.
Holds an ordered {dataSourceName -> PrepAndExpectedTestCase} map, one delegate per data
source - normally a DefaultPrepAndExpectedTestCase bound to its own
IDatabaseTester. preTest(Map) sets each involved delegate up in the map's
declared order; postTest(boolean) verifies and cleans each up in reverse order,
collecting every delegate's failure into one MultiDataSourceAssertionError instead of
stopping at the first; runTest(Map, PrepAndExpectedTestCaseSteps) runs the test steps
exactly once in between. This class does not implement PrepAndExpectedTestCase itself -
that interface's singular accessors and lifecycle methods have no honest answer for N data
sources - and it drives each delegate only through that interface's own public
preTest/postTest methods, never a reimplemented verify or cleanup.
The data source name to PrepAndExpectedTestCase wiring is fixed for this instance's
life: assemble it with the constructors, from(String, PrepAndExpectedTestCase), the
forTesters(...) factories, and add(String, PrepAndExpectedTestCase) /
add(String, IDatabaseTester) / addAll(Map), all of which return this instance
so they chain; the wiring is then frozen on the first preTest(Map) /
runTest(Map, PrepAndExpectedTestCaseSteps) call, and a further add throws
IllegalStateException. The {dataSourceName -> PrepAndExpectedTestData} map each
test run passes to preTest(Map) / runTest(Map, PrepAndExpectedTestCaseSteps)
varies per call; a wired data source absent from that map, or mapped to the exact
PrepAndExpectedTestData.NONE instance, sits that run out entirely - its connection is
never opened.
This instance is not thread-safe, but is safe to reuse sequentially - across
@ParameterizedTest rows, or as a longer-lived singleton reused across test classes -
since each preTest(Map) / runTest(Map, PrepAndExpectedTestCaseSteps) /
postTest(boolean) call, including its own teardown, completes before the next begins.
- Since:
- 3.6.0
- Author:
- Jeff Jensen
-
Constructor Summary
ConstructorsConstructorDescriptionCreates an empty instance for the delegate currency: assemble it withadd(String, PrepAndExpectedTestCase)/addAll(Map).MultiDataSourcePrepAndExpectedTestCase(Map<String, ? extends PrepAndExpectedTestCase> testCasesByDataSourceName) Creates an instance seeded with the given delegates, in the given map's iteration order. -
Method Summary
Modifier and TypeMethodDescriptionadd(String dataSourceName, IDatabaseTester tester) Wires one data source to a newDefaultPrepAndExpectedTestCasebound to the given tester, sharing this instance's loader andcloseConnectionAfterTest.add(String dataSourceName, PrepAndExpectedTestCase testCase) Wires one data source to the given delegate.addAll(Map<String, ? extends PrepAndExpectedTestCase> testCasesByDataSourceName) Wires every entry of the given map, in its iteration order.forTesters(DataFileLoader dataFileLoader) Creates an empty instance for the tester currency -add(String, IDatabaseTester)wraps each tester in aDefaultPrepAndExpectedTestCasesharing the given loader, withcloseConnectionAfterTesttrue.forTesters(DataFileLoader dataFileLoader, boolean closeConnectionAfterTest) Creates an empty instance for the tester currency, asforTesters(DataFileLoader)does, with the givencloseConnectionAfterTestapplied to everyadd(String, IDatabaseTester)-wrapped delegate.forTesters(DataFileLoader dataFileLoader, Map<String, ? extends IDatabaseTester> testersByDataSourceName) Creates an instance for the tester currency, seeded with the given testers - asforTesters(DataFileLoader)does, thenadd(String, IDatabaseTester)for each entry, in the given map's iteration order.forTesters(DataFileLoader dataFileLoader, Map<String, ? extends IDatabaseTester> testersByDataSourceName, boolean closeConnectionAfterTest) Creates an instance for the tester currency, seeded with the given testers, asforTesters(DataFileLoader, Map)does, with the givencloseConnectionAfterTestapplied to every wrapped delegate.from(String dataSourceName, PrepAndExpectedTestCase testCase) Creates an instance seeded with one data source, for the delegate currency.Returns the wired data source names, in declared order.getTestCase(String dataSourceName) Returns the delegate wired to one data source, for a test that needs to reach one directly - e.g. to assert something extra on it, or to inspect it after a failure.voidpostTest(boolean verifyData) Verifies and cleans up every involved data source, in reverse declared order.voidpreTest(Map<String, PrepAndExpectedTestData> dataByDataSourceName) Sets up every involved data source's prep data, in declared order.runTest(Map<String, PrepAndExpectedTestData> dataByDataSourceName, PrepAndExpectedTestCaseSteps testSteps) Runs the full lifecycle once:preTest(Map), then the given test steps exactly once, thenpostTest(true).
-
Constructor Details
-
MultiDataSourcePrepAndExpectedTestCase
public MultiDataSourcePrepAndExpectedTestCase()Creates an empty instance for the delegate currency: assemble it withadd(String, PrepAndExpectedTestCase)/addAll(Map). -
MultiDataSourcePrepAndExpectedTestCase
public MultiDataSourcePrepAndExpectedTestCase(Map<String, ? extends PrepAndExpectedTestCase> testCasesByDataSourceName) Creates an instance seeded with the given delegates, in the given map's iteration order.- Parameters:
testCasesByDataSourceName- The delegates to seed this instance with, keyed by data source name; notnull, and not containing anullor blank key or anullvalue. Defensively copied; mutating this map afterward does not affect this instance.- Throws:
IllegalArgumentException- If testCasesByDataSourceName isnull, or contains anullor blank key, or anullvalue.
-
-
Method Details
-
from
public static MultiDataSourcePrepAndExpectedTestCase from(String dataSourceName, PrepAndExpectedTestCase testCase) Creates an instance seeded with one data source, for the delegate currency.- Parameters:
dataSourceName- The data source name; notnullor blank.testCase- The delegate for that data source; notnull.- Returns:
- The new instance, so further
add/addAllcalls can chain off it. - Throws:
IllegalArgumentException- If dataSourceName isnullor blank, or if testCase isnull.
-
forTesters
Creates an empty instance for the tester currency -add(String, IDatabaseTester)wraps each tester in aDefaultPrepAndExpectedTestCasesharing the given loader, withcloseConnectionAfterTesttrue.- Parameters:
dataFileLoader- The loader everyadd(String, IDatabaseTester)-wrapped delegate shares.- Returns:
- The new instance.
-
forTesters
public static MultiDataSourcePrepAndExpectedTestCase forTesters(DataFileLoader dataFileLoader, boolean closeConnectionAfterTest) Creates an empty instance for the tester currency, asforTesters(DataFileLoader)does, with the givencloseConnectionAfterTestapplied to everyadd(String, IDatabaseTester)-wrapped delegate.- Parameters:
dataFileLoader- The loader everyadd(String, IDatabaseTester)-wrapped delegate shares.closeConnectionAfterTest- Whether eachadd(String, IDatabaseTester)-wrapped delegate closes its connection after each test; false to reuse each delegate's connection across@ParameterizedTestrows, as for a loneDefaultPrepAndExpectedTestCase.- Returns:
- The new instance.
-
forTesters
public static MultiDataSourcePrepAndExpectedTestCase forTesters(DataFileLoader dataFileLoader, Map<String, ? extends IDatabaseTester> testersByDataSourceName) Creates an instance for the tester currency, seeded with the given testers - asforTesters(DataFileLoader)does, thenadd(String, IDatabaseTester)for each entry, in the given map's iteration order.- Parameters:
dataFileLoader- The loader every wrapped delegate shares.testersByDataSourceName- The testers to seed this instance with, keyed by data source name; notnull.- Returns:
- The new instance.
- Throws:
IllegalArgumentException- If testersByDataSourceName isnull, or contains anullor blank key, or anullvalue.
-
forTesters
public static MultiDataSourcePrepAndExpectedTestCase forTesters(DataFileLoader dataFileLoader, Map<String, ? extends IDatabaseTester> testersByDataSourceName, boolean closeConnectionAfterTest) Creates an instance for the tester currency, seeded with the given testers, asforTesters(DataFileLoader, Map)does, with the givencloseConnectionAfterTestapplied to every wrapped delegate.- Parameters:
dataFileLoader- The loader every wrapped delegate shares.testersByDataSourceName- The testers to seed this instance with, keyed by data source name; notnull.closeConnectionAfterTest- Whether each wrapped delegate closes its connection after each test.- Returns:
- The new instance.
- Throws:
IllegalArgumentException- If testersByDataSourceName isnull, or contains anullor blank key, or anullvalue.
-
add
public MultiDataSourcePrepAndExpectedTestCase add(String dataSourceName, PrepAndExpectedTestCase testCase) Wires one data source to the given delegate.- Parameters:
dataSourceName- The data source name; notnullor blank, and not already wired.testCase- The delegate for that data source; notnull.- Returns:
- This instance, so calls can chain.
- Throws:
IllegalArgumentException- If dataSourceName isnull, blank, or already wired, or if testCase isnull.IllegalStateException- If the wiring is already frozen by an earlierpreTest(Map)/runTest(Map, PrepAndExpectedTestCaseSteps)call.
-
add
Wires one data source to a newDefaultPrepAndExpectedTestCasebound to the given tester, sharing this instance's loader andcloseConnectionAfterTest.- Parameters:
dataSourceName- The data source name; notnullor blank, and not already wired.tester- The tester for that data source; notnull.- Returns:
- This instance, so calls can chain.
- Throws:
IllegalArgumentException- If dataSourceName isnull, blank, or already wired, or if tester isnull.IllegalStateException- If this instance was not created via one of theforTesters(...)factories, or if the wiring is already frozen.
-
addAll
public MultiDataSourcePrepAndExpectedTestCase addAll(Map<String, ? extends PrepAndExpectedTestCase> testCasesByDataSourceName) Wires every entry of the given map, in its iteration order.- Parameters:
testCasesByDataSourceName- The delegates to add, keyed by data source name; notnull.- Returns:
- This instance, so calls can chain.
- Throws:
IllegalArgumentException- If testCasesByDataSourceName isnull, or contains anullor blank key, an already-wired key, or anullvalue.IllegalStateException- If the wiring is already frozen by an earlierpreTest(Map)/runTest(Map, PrepAndExpectedTestCaseSteps)call.
-
runTest
public Object runTest(Map<String, PrepAndExpectedTestData> dataByDataSourceName, PrepAndExpectedTestCaseSteps testSteps) throws ExceptionRuns the full lifecycle once:preTest(Map), then the given test steps exactly once, thenpostTest(true).A throwable from the test steps is rethrown as-is - not wrapped - with every involved delegate torn down first via
postTest(false)in reverse declared order, each teardown failure attached to the step throwable viaThrowable.addSuppressed(Throwable)- except a teardown failure that is the exact same instance as the step throwable itself, which is dropped rather than attempting the self-suppressionThrowable.addSuppressed(Throwable)forbids.- Parameters:
dataByDataSourceName- The prep/expected/verify data for this run, keyed by data source name; a wired data source absent from this map, or mapped toPrepAndExpectedTestData.NONE, sits this run out entirely.testSteps- The test steps to run, exactly once.- Returns:
- The user-defined object the test steps returned.
- Throws:
Exception- IfpreTest(Map)fails, if the test steps fail, or ifpostTest(boolean)fails.
-
preTest
Sets up every involved data source's prep data, in declared order.A wired data source absent from
dataByDataSourceName, or mapped to the exactPrepAndExpectedTestData.NONEinstance, is skipped entirely this run - itspreTestis never called and its connection is never opened. An unknown key indataByDataSourceName- one not wired to this instance - is rejected before any delegate is touched.If an involved delegate's own
preTestfails, every involved delegate set up so far - including the one that just failed - is rolled back, viapostTest(false), in reverse order, never a barecleanupData()- with each rollback failure attached to the original failure viaThrowable.addSuppressed(Throwable), except a rollback failure that is the exact same instance as the original failure, which is dropped rather than attempting the self-suppressionThrowable.addSuppressed(Throwable)forbids; the original failure is then rethrown as-is.- Parameters:
dataByDataSourceName- The prep/expected/verify data for this run, keyed by data source name; notnull, and containing no key this instance has no delegate wired for.- Throws:
IllegalStateException- If no data source is wired yet.IllegalArgumentException- If dataByDataSourceName isnull, contains an unknown data source name, or maps a wired data source name tonull.Exception- If an involved delegate's ownpreTestfails.
-
postTest
Verifies and cleans up every involved data source, in reverse declared order.Every involved delegate's own
PrepAndExpectedTestCase.postTest(boolean)runs - verify (or, whenverifyDatais false, its own row count baseline discard) and cleanup - even if an earlier one in this reverse order failed; every collected failure is then aggregated into oneMultiDataSourceAssertionErrorrather than the first one stopping the rest from being torn down.- Parameters:
verifyData- True to verify each involved delegate's data before cleaning it up; false to skip verification (the test steps already failed) and just clean up.- Throws:
MultiDataSourceAssertionError- If one or more involved delegates failed their ownpostTest.Exception
-
getDataSourceNames
Returns the wired data source names, in declared order.- Returns:
- An unmodifiable view of the wired data source names, in declared order.
-
getTestCase
Returns the delegate wired to one data source, for a test that needs to reach one directly - e.g. to assert something extra on it, or to inspect it after a failure.- Parameters:
dataSourceName- The data source name.- Returns:
- The delegate wired to that data source.
- Throws:
IllegalArgumentException- If no data source with that name is wired.
-