DB Tester Specification - Test Framework Integration
JUnit Integration
Module
db-tester-junit
Extension Class
Location: io.github.seijikohara.dbtester.junit.jupiter.extension.DatabaseTestExtension
Implemented Interfaces:
BeforeEachCallback- DataSet phase executionAfterEachCallback- ExpectedDataSet phase verificationParameterResolver-ExtensionContextinjection
Registration
@ExtendWith(DatabaseTestExtension.class)
class UserRepositoryTest {
// ...
}DataSource Registration
Register data sources in @BeforeAll:
@ExtendWith(DatabaseTestExtension.class)
class UserRepositoryTest {
@BeforeAll
static void setup(ExtensionContext context) {
var registry = DatabaseTestExtension.getRegistry(context);
registry.registerDefault(dataSource);
}
@Test
@DataSet
@ExpectedDataSet
void testCreateUser() {
// Test implementation
}
}Configuration Customization
@BeforeAll
static void setup(ExtensionContext context) {
var registry = DatabaseTestExtension.getRegistry(context);
registry.registerDefault(dataSource);
var config = Configuration.builder()
.conventions(ConventionSettings.builder()
.dataFormat(DataFormat.TSV)
.build())
.build();
DatabaseTestExtension.setConfiguration(context, config);
}Static Methods
| Method | Description |
|---|---|
getRegistry(ExtensionContext) | Returns or creates DataSourceRegistry |
setConfiguration(ExtensionContext, Configuration) | Sets custom configuration |
Nested Test Classes
The extension shares state across nested test classes:
@ExtendWith(DatabaseTestExtension.class)
class UserRepositoryTest {
@BeforeAll
static void setup(ExtensionContext context) {
var registry = DatabaseTestExtension.getRegistry(context);
registry.registerDefault(dataSource);
}
@Nested
class CreateTests {
@Test
@DataSet
@ExpectedDataSet
void testCreateUser() { } // Uses parent's registry
}
@Nested
class UpdateTests {
@Test
@DataSet
@ExpectedDataSet
void testUpdateUser() { } // Uses parent's registry
}
}Annotation Precedence
Method-level annotations override class-level:
@DataSet(operation = Operation.CLEAN_INSERT) // Class default
class UserRepositoryTest {
@Test
@DataSet(operation = Operation.INSERT) // Overrides class
void testWithInsert() { }
@Test
@DataSet // Uses class default
void testWithDefault() { }
}Spock Integration
Module
db-tester-spock
Extension Class
Location: io.github.seijikohara.dbtester.spock.extension.DatabaseTestExtension
Type: Annotation-driven extension (IAnnotationDrivenExtension<DatabaseTest>)
Registration
Add @DatabaseTest to the specification class and implement the DatabaseTestSupport trait to activate the extension:
@DatabaseTest
class UserRepositorySpec extends Specification implements DatabaseTestSupport {
DataSourceRegistry dbTesterRegistry = new DataSourceRegistry()
def setupSpec() {
dbTesterRegistry.registerDefault(dataSource)
}
@DataSet
@ExpectedDataSet
def 'should create user'() {
// Test implementation
}
}DatabaseTestSupport Trait
The DatabaseTestSupport trait provides the contract for database testing:
| Property | Type | Required | Description |
|---|---|---|---|
dbTesterRegistry | DataSourceRegistry | Yes | Data source registration |
dbTesterConfiguration | Configuration | No | Custom configuration (defaults to Configuration.defaults()) |
Configuration Customization
Override getDbTesterConfiguration() in the specification:
@DatabaseTest
class UserRepositorySpec extends Specification implements DatabaseTestSupport {
DataSourceRegistry dbTesterRegistry = new DataSourceRegistry()
Configuration dbTesterConfiguration = Configuration.builder()
.conventions(ConventionSettings.builder()
.dataFormat(DataFormat.TSV)
.build())
.build()
def setupSpec() {
dbTesterRegistry.registerDefault(dataSource)
}
@DataSet
@ExpectedDataSet
def 'should create user'() { }
}
### Feature Method Naming
The scenario name is derived from the feature method:
```groovy
@DataSet
def 'should create user with email'() {
// Scenario name: "should create user with email"
}Data-Driven Tests
For parameterized tests with where: blocks, Spock uses the iteration name:
@DataSet
def 'should process #status order'() {
expect:
// Test implementation
where:
status << ['PENDING', 'COMPLETED']
}Scenario names: "should process PENDING order", "should process COMPLETED order"
Kotest Integration
Module
db-tester-kotest
Extension Class
Location: io.github.seijikohara.dbtester.kotest.extension.DatabaseTestExtension
Type: TestCaseExtension - Intercepts test case execution for data set and expected data set phases.
Registration
Simplified approach with @DatabaseTest (recommended):
The @DatabaseTest annotation registers DatabaseTestExtension automatically. The specification class must implement the DatabaseTestSupport interface:
@DatabaseTest
class UserRepositorySpec : AnnotationSpec(), DatabaseTestSupport {
override val dbTesterRegistry = DataSourceRegistry()
private lateinit var dataSource: DataSource
@BeforeAll
fun setupSpec() {
dataSource = createDataSource()
dbTesterRegistry.registerDefault(dataSource)
}
@Test
@DataSet
@ExpectedDataSet
fun `should create user`() {
// Test implementation
}
}Explicit extension registration:
Register the extension in the init block. In Kotest 6, the extensions() method is final:
class UserRepositorySpec : AnnotationSpec(), DatabaseTestSupport {
override val dbTesterRegistry = DataSourceRegistry()
init {
extensions(DatabaseTestExtension())
}
@BeforeAll
fun setupSpec() {
dbTesterRegistry.registerDefault(dataSource)
}
@Test
@DataSet
@ExpectedDataSet
fun `should create user`() {
// Test implementation
}
}DatabaseTestSupport Interface
The DatabaseTestSupport interface provides the contract for database testing:
| Property | Type | Required | Description |
|---|---|---|---|
dbTesterRegistry | DataSourceRegistry | Yes | Data source registration |
dbTesterConfiguration | Configuration | No | Custom configuration (defaults to Configuration.defaults()) |
DataSource Registration
Implement the DatabaseTestSupport interface and override dbTesterRegistry:
@DatabaseTest
class UserRepositorySpec : AnnotationSpec(), DatabaseTestSupport {
override val dbTesterRegistry = DataSourceRegistry()
@BeforeAll
fun setupSpec() {
dbTesterRegistry.registerDefault(dataSource)
dbTesterRegistry.register("secondary", secondaryDataSource)
}
}Configuration Customization
Override dbTesterConfiguration in the interface implementation:
@DatabaseTest
class UserRepositorySpec : AnnotationSpec(), DatabaseTestSupport {
override val dbTesterRegistry = DataSourceRegistry()
override val dbTesterConfiguration = Configuration.builder()
.conventions(ConventionSettings.builder()
.dataFormat(DataFormat.TSV)
.build())
.build()
}Test Method Naming
Use backtick method names for descriptive test names:
@Test
@DataSet
fun `should create user with email`() {
// Scenario name: "should create user with email"
}AnnotationSpec Requirement
DB Tester requires AnnotationSpec style for Kotest integration because:
- Annotations (
@DataSet,@ExpectedDataSet) can be applied to test methods - Method resolution via reflection is reliable
- Familiar JUnit-like structure for Java developers
Spring Boot Integration
JUnit Spring Boot Starter
Module: db-tester-junit-spring-boot-starter
Extension: SpringBootDatabaseTestExtension
Automatic DataSource Discovery
The Spring Boot extension performs these steps automatically:
- Detects the Spring
ApplicationContext - Finds
DataSourcebeans - Registers the beans with
DataSourceRegistry
@SpringBootTest
@ExtendWith(SpringBootDatabaseTestExtension.class)
class UserRepositoryTest {
@Test
@DataSet
@ExpectedDataSet
void testCreateUser() {
// DataSource automatically registered from Spring context
}
}Multiple DataSources
For multiple data sources, use @Qualifier:
@Configuration
class DataSourceConfig {
@Bean
@Primary
DataSource primaryDataSource() { }
@Bean
@Qualifier("secondary")
DataSource secondaryDataSource() { }
}@SpringBootTest
@ExtendWith(SpringBootDatabaseTestExtension.class)
class MultiDatabaseTest {
@Test
@DataSet(sources = {
@DataSetSource(dataSourceName = ""), // Primary (default)
@DataSetSource(dataSourceName = "secondary") // Secondary
})
void testMultipleDatabases() { }
}Configuration Properties
Configure via application.properties or application.yml:
# Enable or disable DB Tester (default: true)
db-tester.enabled=true
# Auto-register DataSource beans (default: true)
db-tester.auto-register-data-sources=true
# Data format (CSV or TSV)
db-tester.convention.data-format=CSV
# Expectation directory suffix
db-tester.convention.expectation-suffix=/expected
# Scenario marker column name
db-tester.convention.scenario-marker=[Scenario]
# Table merge strategy (FIRST, LAST, UNION, UNION_ALL)
db-tester.convention.table-merge-strategy=UNION_ALL
# Default preparation operation
db-tester.operation.preparation=CLEAN_INSERT
# Default expectation operation (typically NONE for verification only)
db-tester.operation.expectation=NONEProperty names use singular form (convention, operation).
Spock Spring Boot Starter
Module: db-tester-spock-spring-boot-starter
Extension: SpringBootDatabaseTestExtension (Groovy)
Type: Annotation-driven extension (IAnnotationDrivenExtension<SpringBootDatabaseTest>)
@SpringBootTest
@SpringBootDatabaseTest
class UserRepositorySpec extends Specification {
@DataSet
@ExpectedDataSet
def 'should create user'() {
// DataSource automatically registered from Spring context
}
}Kotest Spring Boot Starter
Module: db-tester-kotest-spring-boot-starter
Extension: SpringBootDatabaseTestExtension (Kotlin)
Type: TestCaseExtension with automatic Spring ApplicationContext integration.
@SpringBootTest
class UserRepositorySpec : AnnotationSpec() {
@Autowired
private lateinit var userRepository: UserRepository
init {
extensions(SpringBootDatabaseTestExtension())
}
@Test
@DataSet
@ExpectedDataSet
fun `should create user`() {
// DataSource automatically registered from Spring context
}
}Auto-Configuration
Auto-configuration classes:
| Module | Auto-Configuration Class |
|---|---|
| JUnit Starter | DbTesterJUnitAutoConfiguration |
| Spock Starter | DbTesterSpockAutoConfiguration |
| Kotest Starter | DbTesterKotestAutoConfiguration |
Lifecycle Hooks
JUnit Lifecycle
Spock Lifecycle
Kotest Lifecycle
Lifecycle Executor Classes
| Framework | Preparation | Expectation |
|---|---|---|
| JUnit | PreparationExecutor | ExpectationVerifier |
| Spock | SpockPreparationExecutor | SpockExpectationVerifier |
| Kotest | KotestPreparationExecutor | KotestExpectationVerifier |
Error Handling
| Phase | Error Type | Behavior |
|---|---|---|
| DataSet | DatabaseOperationException | Test fails before execution |
| Test | Any exception | ExpectedDataSet still runs |
| ExpectedDataSet | ValidationException | Test fails with comparison details |
Related Specifications
- Overview - Framework purpose and key concepts
- Public API - Annotation details
- Configuration - Configuration options
- SPI - Service Provider Interface extension points
- Error Handling - Lifecycle error handling