DB Tester Specification - Configuration
Configuration Class
Aggregates the runtime configuration for the database testing extension.
Location: io.github.seijikohara.dbtester.api.config.Configuration
Type: final class with builder pattern
Components
| Component | Type | Description |
|---|---|---|
conventions | ConventionSettings | Dataset directory resolution rules and naming conventions |
verification | VerificationSettings | Verification behavior for expectation phase |
execution | ExecutionSettings | Execution behavior for database operations |
operations | OperationDefaults | Default database operations |
loader | DataSetLoader | Dataset loading strategy |
Factory Methods
| Method | Description |
|---|---|
builder() | Creates a new builder for constructing Configuration instances |
defaults() | Creates configuration with all framework defaults |
Instance Methods
| Method | Description |
|---|---|
toBuilder() | Creates a new builder initialized with values from this instance |
Builder Methods
| Method | Description |
|---|---|
conventions(ConventionSettings) | Sets the resolution rules for locating datasets |
verification(VerificationSettings) | Sets the verification behavior for expectation phase |
execution(ExecutionSettings) | Sets the execution behavior for database operations |
operations(OperationDefaults) | Sets the default database operations |
loader(DataSetLoader) | Sets the strategy for constructing datasets |
build() | Builds a new Configuration instance |
Default Behavior
When Configuration.defaults() is used:
- Conventions:
ConventionSettings.standard() - Operations:
OperationDefaults.standard() - Loader: Loaded via ServiceLoader from
DataSetLoaderProvider - Verification:
VerificationSettings.standard() - Execution:
ExecutionSettings.standard()
Usage Example
// Using defaults
var config = Configuration.defaults();
// Customizing with builder
var config = Configuration.builder()
.conventions(ConventionSettings.builder()
.dataFormat(DataFormat.TSV)
.build())
.verification(VerificationSettings.builder()
.rowOrdering(RowOrdering.UNORDERED)
.build())
.execution(ExecutionSettings.builder()
.queryTimeout(Duration.ofSeconds(30))
.build())
.operations(OperationDefaults.builder()
.preparation(Operation.TRUNCATE_INSERT)
.build())
.build();
// JUnit example - customize configuration in @BeforeAll
@BeforeAll
static void setup(ExtensionContext context) {
var config = Configuration.builder()
.conventions(ConventionSettings.builder()
.dataFormat(DataFormat.TSV)
.build())
.build();
DatabaseTestExtension.setConfiguration(context, config);
}ConventionSettings
Defines naming conventions for dataset discovery and scenario filtering.
Location: io.github.seijikohara.dbtester.api.config.ConventionSettings
Type: final class with builder pattern
Fields
| Field | Type | Default | Description |
|---|---|---|---|
baseDirectory | @Nullable String | null | Absolute or relative base path; null for classpath-relative |
expectationSuffix | String | "/expected" | Subdirectory for expected datasets |
scenarioMarker | String | "[Scenario]" | Column name for scenario filtering |
dataFormat | DataFormat | AUTO | File format for dataset files |
tableMergeStrategy | TableMergeStrategy | UNION_ALL | Strategy for merging duplicate tables |
loadOrderFileName | String | "load-order.txt" | File name for table loading order specification |
Factory Methods
| Method | Description |
|---|---|
builder() | Creates a new builder for constructing ConventionSettings instances |
standard() | Creates settings with all defaults |
Instance Methods
| Method | Description |
|---|---|
toBuilder() | Creates a new builder initialized with values from this instance |
Builder Methods
| Method | Description |
|---|---|
baseDirectory(String) | Sets the base directory (null for classpath-relative) |
expectationSuffix(String) | Sets the expectation suffix |
scenarioMarker(String) | Sets the scenario marker |
dataFormat(DataFormat) | Sets the data format |
tableMergeStrategy(TableMergeStrategy) | Sets the merge strategy |
loadOrderFileName(String) | Sets the load order file name |
build() | Builds a new ConventionSettings instance |
With Methods (Fluent Copy)
| Method | Description |
|---|---|
withBaseDirectory(String) | Creates copy with specified base directory (null for classpath-relative) |
withExpectationSuffix(String) | Creates copy with specified expectation suffix |
withScenarioMarker(String) | Creates copy with specified scenario marker |
withDataFormat(DataFormat) | Creates copy with specified format |
withTableMergeStrategy(TableMergeStrategy) | Creates copy with specified merge strategy |
withLoadOrderFileName(String) | Creates copy with specified load order file name |
Directory Resolution
When baseDirectory is null (default), the framework resolves datasets relative to the test class:
src/test/resources/
└── {test.class.package}/{TestClassName}/
├── TABLE1.csv # Preparation dataset
├── TABLE2.csv
├── load-order.txt # Table ordering (optional)
└── expected/ # Expectation datasets (suffix configurable)
├── TABLE1.csv
└── TABLE2.csvWhen baseDirectory is specified:
{baseDirectory}/
├── TABLE1.csv
├── load-order.txt
└── expected/
└── TABLE1.csvExpectedDataSet Suffix
The expectationSuffix appends to the DataSet path:
| DataSet Path | Suffix | ExpectedDataSet Path |
|---|---|---|
com/example/UserTest | /expected | com/example/UserTest/expected |
/data/test | /expected | /data/test/expected |
custom/path | /verify | custom/path/verify |
Advanced Configuration Example
// Configure retry, timeout, and unordered comparison
var config = Configuration.builder()
.conventions(ConventionSettings.builder()
.build())
.verification(VerificationSettings.builder()
.rowOrdering(RowOrdering.UNORDERED)
.retryCount(3)
.retryDelay(Duration.ofMillis(500))
.globalExcludeColumns(Set.of("CREATED_AT", "UPDATED_AT"))
.globalColumnStrategies(Map.of(
"EMAIL", ColumnStrategyMapping.caseInsensitive("EMAIL"),
"VERSION", ColumnStrategyMapping.ignore("VERSION")
))
.build())
.execution(ExecutionSettings.builder()
.queryTimeout(Duration.ofSeconds(30))
.transactionMode(TransactionMode.AUTO_COMMIT)
.build())
.build();VerificationSettings
Defines verification behavior for expectation phase validation.
Location: io.github.seijikohara.dbtester.api.config.VerificationSettings
Type: final class with builder pattern
Fields
| Field | Type | Default | Description |
|---|---|---|---|
globalExcludeColumns | Set<String> | Set.of() | Column names to exclude from all verifications (case-insensitive) |
globalColumnStrategies | Map<String, ColumnStrategyMapping> | Map.of() | Column comparison strategies for all verifications |
rowOrdering | RowOrdering | ORDERED | Default row comparison strategy |
retryCount | int | 0 | Retry attempts for verification (0 = no retry) |
retryDelay | Duration | 100ms | Delay between retry attempts |
Factory Methods
| Method | Description |
|---|---|
builder() | Creates a new builder for constructing VerificationSettings instances |
standard() | Creates settings with all defaults |
Instance Methods
| Method | Description |
|---|---|
toBuilder() | Creates a new builder initialized with values from this instance |
Builder Methods
| Method | Description |
|---|---|
globalExcludeColumns(Set<String>) | Sets the global exclude columns |
globalColumnStrategies(Map<String, ColumnStrategyMapping>) | Sets the global column strategies |
rowOrdering(RowOrdering) | Sets the row ordering strategy |
retryCount(int) | Sets the retry count |
retryDelay(Duration) | Sets the retry delay |
build() | Builds a new VerificationSettings instance |
With Methods (Fluent Copy)
| Method | Description |
|---|---|
withGlobalExcludeColumns(Set<String>) | Creates copy with specified global exclude columns |
withGlobalColumnStrategies(Map<String, ColumnStrategyMapping>) | Creates copy with specified global column strategies |
withRowOrdering(RowOrdering) | Creates copy with specified row ordering strategy |
withRetryCount(int) | Creates copy with specified retry count |
withRetryDelay(Duration) | Creates copy with specified retry delay |
ExecutionSettings
Defines execution behavior for database operations.
Location: io.github.seijikohara.dbtester.api.config.ExecutionSettings
Type: final class with builder pattern
Fields
| Field | Type | Default | Description |
|---|---|---|---|
queryTimeout | @Nullable Duration | null | Maximum query wait time; null for no timeout |
transactionMode | TransactionMode | SINGLE_TRANSACTION | Transaction behavior for operations |
Factory Methods
| Method | Description |
|---|---|
builder() | Creates a new builder for constructing ExecutionSettings instances |
of(Duration, TransactionMode) | Creates settings with specified values |
standard() | Creates settings with all defaults |
Instance Methods
| Method | Description |
|---|---|
toBuilder() | Creates a new builder initialized with values from this instance |
Builder Methods
| Method | Description |
|---|---|
queryTimeout(Duration) | Sets the query timeout (null for no timeout) |
transactionMode(TransactionMode) | Sets the transaction mode |
build() | Builds a new ExecutionSettings instance |
With Methods (Fluent Copy)
| Method | Description |
|---|---|
withQueryTimeout(Duration) | Creates copy with specified query timeout (null for no timeout) |
withTransactionMode(TransactionMode) | Creates copy with specified transaction mode |
DataSourceRegistry
Thread-safe registry for javax.sql.DataSource instances.
Location: io.github.seijikohara.dbtester.api.config.DataSourceRegistry
Thread Safety
- Uses
ConcurrentHashMapfor named data sources - Uses
volatilefield for default data source registerDefault()andclear()aresynchronized
Registration Methods
| Method | Description |
|---|---|
registerDefault(DataSource) | Registers the default data source |
register(String, DataSource) | Registers a named data source; if name is empty, delegates to registerDefault() |
Retrieval Methods
| Method | Return Type | Description |
|---|---|---|
getDefault() | DataSource | Returns default; throws if not registered |
get(String) | DataSource | Returns named or default; throws if not found |
Query Methods
| Method | Return Type | Description |
|---|---|---|
hasDefault() | boolean | Checks if default is registered |
has(String) | boolean | Checks if named data source exists |
Management Methods
| Method | Description |
|---|---|
clear() | Removes all registered data sources |
Resolution Priority
When calling get(name):
- If name is non-empty, look up by name
- If name is empty or not found, fall back to default
- If neither found, throw
DataSourceNotFoundException
Usage Example
@BeforeAll
static void setup(ExtensionContext context) {
var registry = DatabaseTestExtension.getRegistry(context);
// Single database
registry.registerDefault(primaryDataSource);
// Multiple databases
registry.register("primary", primaryDataSource);
registry.register("secondary", secondaryDataSource);
}OperationDefaults
Defines default database operations for preparation and expectation phases.
Location: io.github.seijikohara.dbtester.api.config.OperationDefaults
Type: final class with builder pattern
Fields
| Field | Type | Default | Description |
|---|---|---|---|
preparation | Operation | CLEAN_INSERT | Default operation executed before test runs |
expectation | Operation | NONE | Default operation executed after test completes |
floatingPointEpsilon | double | 1e-6 | Epsilon value for floating-point comparisons |
batchSize | int | 0 | Number of rows per batch for INSERT operations; zero means single batch |
Factory Methods
| Method | Description |
|---|---|
builder() | Creates a new builder for constructing OperationDefaults instances |
standard() | Creates defaults with CLEAN_INSERT for preparation, NONE for expectation, 1e-6 for epsilon, and 0 for batch size |
Instance Methods
| Method | Description |
|---|---|
toBuilder() | Creates a new builder initialized with values from this instance |
Builder Methods
| Method | Description |
|---|---|
preparation(Operation) | Sets the default operation for preparation phase |
expectation(Operation) | Sets the default operation for expectation phase |
floatingPointEpsilon(double) | Sets the epsilon value for floating-point comparisons |
batchSize(int) | Sets the number of rows per batch for INSERT operations (zero or positive) |
build() | Builds a new OperationDefaults instance |
With Methods (Fluent Copy)
| Method | Description |
|---|---|
withPreparation(Operation) | Creates copy with specified preparation operation |
withExpectation(Operation) | Creates copy with specified expectation operation |
withFloatingPointEpsilon(double) | Creates copy with specified floating-point epsilon |
withBatchSize(int) | Creates copy with specified batch size |
DataFormat
Defines supported file formats for dataset files.
Location: io.github.seijikohara.dbtester.api.config.DataFormat
Type: enum
Values
| Value | Extension | Field Separator | Default |
|---|---|---|---|
AUTO | All supported | -- | Yes |
CSV | .csv | Comma (,) | No |
TSV | .tsv | Tab (\t) | No |
JSON | .json | -- | No |
YAML | .yaml | -- | No |
Methods
| Method | Return Type | Description |
|---|---|---|
hasExtension() | boolean | Returns false for AUTO, true for all other formats |
getExtension() | String | Returns file extension including dot; throws UnsupportedOperationException for AUTO |
File Discovery
When loading datasets from a directory:
- List all files matching the configured format extension (or all supported extensions for
AUTO) - Parse each file as a table (filename without extension = table name)
- Ignore files with unsupported extensions
- For
AUTOmode: throwDataSetLoadExceptionif the same table name exists in multiple formats
TableMergeStrategy
Defines how tables from multiple datasets merge.
Location: io.github.seijikohara.dbtester.api.config.TableMergeStrategy
Type: enum
Values
| Value | Description | Example |
|---|---|---|
FIRST | Keep only first occurrence | [A,B] + [C,D] = [A,B] |
LAST | Keep only last occurrence | [A,B] + [C,D] = [C,D] |
UNION | Merge and deduplicate | [A,B] + [B,C] = [A,B,C] |
UNION_ALL | Merge and keep duplicates (default) | [A,B] + [B,C] = [A,B,B,C] |
Merge Behavior
Datasets process in annotation declaration order:
@DataSet(sources = {
@DataSetSource(resourceLocation = "dataset1"), // Processed first
@DataSetSource(resourceLocation = "dataset2") // Processed second
})When both datasets contain the same table:
| Strategy | Result |
|---|---|
FIRST | Use table from dataset1 only |
LAST | Use table from dataset2 only |
UNION | Combine rows, remove exact duplicates |
UNION_ALL | Combine all rows, keep duplicates |
Strategy Selection Guide
Choose the merge strategy based on your use case:
| Strategy | When to Use | Example Scenario |
|---|---|---|
UNION_ALL (default) | Most use cases; preserves all rows including duplicates | Loading base data + scenario-specific overrides with intentional duplicates |
UNION | Combining datasets with overlapping rows; deduplicate | Merging reference data from multiple sources without duplicates |
LAST | Override entire table with latest dataset | Production-like base data + test-specific complete replacement |
FIRST | Keep only base dataset; ignore subsequent datasets | Shared base data + optional per-test overrides (ignore if present) |
Row Equality in UNION
UNION determines row equality by comparing cell values using CellValue.equals(). Two rows are considered equal if all corresponding column values are equal.
Values from all data formats (CSV, TSV, JSON, YAML) normalize to strings during parsing, so deduplication compares string representations. For example, a CSV value 1 and a JSON value 1 (integer) both become the string "1" and are treated as equal.
RowOrdering
Defines how rows are compared during expectation verification.
Location: io.github.seijikohara.dbtester.api.config.RowOrdering
Type: enum
Values
| Value | Description |
|---|---|
ORDERED | Positional comparison (row-by-row by index). Default behavior. |
UNORDERED | Set-based comparison (rows matched regardless of position) |
When to Use
| Mode | Use Case |
|---|---|
ORDERED | Query includes ORDER BY; row order is significant; maximum performance |
UNORDERED | No ORDER BY; row order not significant; database may return rows in unpredictable order |
Configuration
Row ordering can be configured at two levels:
- Annotation-level: Per-test via
@ExpectedDataSet(rowOrdering = ...) - Global: Via
VerificationSettings.withRowOrdering()
Annotation-level configuration takes precedence over global settings.
Performance Considerations
Unordered comparison has O(n*m) complexity in the worst case, where n is the expected row count and m is the actual row count. For large datasets, consider:
- Using
ORDEREDwith ORDER BY in queries - Limiting the dataset size
- Using primary key columns for deterministic ordering
TransactionMode
Defines transaction behavior for database operations.
Location: io.github.seijikohara.dbtester.api.config.TransactionMode
Type: enum
Values
| Value | Description |
|---|---|
AUTO_COMMIT | Each statement committed immediately (autoCommit = true) |
SINGLE_TRANSACTION | All statements in single transaction (default) |
NONE | No transaction management (connection state unchanged) |
When to Use
| Mode | Use Case |
|---|---|
AUTO_COMMIT | Foreign key constraints prevent transactional insertion; debugging |
SINGLE_TRANSACTION | Atomic all-or-nothing operations (recommended) |
NONE | External transaction management (Spring's @Transactional) |
Configuration Example
var config = Configuration.builder()
.execution(ExecutionSettings.builder()
.transactionMode(TransactionMode.AUTO_COMMIT)
.build())
.build();Rollback Behavior
| Mode | On Failure |
|---|---|
AUTO_COMMIT | Partial data may remain; cannot rollback |
SINGLE_TRANSACTION | Complete rollback; no partial data |
NONE | Depends on external transaction manager |
TestContext
Immutable snapshot of test execution context.
Location: io.github.seijikohara.dbtester.api.context.TestContext
Type: record
Fields
| Field | Type | Description |
|---|---|---|
testClass | Class<?> | Test class containing the method |
testMethod | Method | Currently executing test method |
configuration | Configuration | Active framework configuration |
registry | DataSourceRegistry | Registered data sources |
Purpose
TestContext provides a framework-agnostic representation of test execution state. Test framework extensions (JUnit, Spock, and Kotest) create TestContext instances from their native context objects.
Usage
// Created by framework extensions
var configuration = Configuration.builder()
.conventions(ConventionSettings.standard())
.operations(OperationDefaults.standard())
.loader(loader)
.build();
TestContext context = new TestContext(
testClass,
testMethod,
configuration,
registry
);
// Used by loaders and executors
List<TableSet> tableSets = loader.loadPreparationDataSets(context);Related Specifications
- Overview - Framework purpose and key concepts
- Public API - Annotations and interfaces
- Data Formats - AUTO detection, CSV, TSV, JSON, and YAML file structure
- Database Operations - Supported operations
- Test Frameworks - JUnit, Spock, and Kotest integration
- Error Handling - Error messages and exception types