Framework Comparison
This page compares DB Tester with other database testing frameworks in the Java/JVM ecosystem.
Executive Summary
| Framework | Best For | Trade-offs |
|---|---|---|
| DB Tester | Convention-based testing with JUnit 6/Spock 2/Kotest 6 | Limited data formats, newer project |
| DBUnit | Extensive format support and customization | Verbose configuration, no JUnit 5 |
| Database Rider | Comprehensive annotation-driven testing | Complex dependency tree |
| Spring Test DBUnit | Spring-centric projects | Spring-only, aging project |
| DbSetup | Code-only setup without external files | No assertion capabilities |
| JDBDT | Incremental change verification | Smaller community |
Testcontainers
Testcontainers complements these frameworks. Testcontainers provides database infrastructure (Docker containers), while these frameworks manage test data. Use them together.
Detailed Feature Comparison
Test Framework Integration
| Feature | DB Tester | DBUnit | Database Rider | Spring Test DBUnit | DbSetup | JDBDT |
|---|---|---|---|---|---|---|
| JUnit 6 | Yes | - | - | - | - | - |
| JUnit 5 | - | - | Yes | - | Yes | Yes |
| JUnit 4 | - | Yes | Yes | Yes | Yes | Yes |
| Spock 2 | Yes | - | DSL* | - | Yes | - |
| Kotest | Yes | - | - | - | - | - |
| TestNG | - | Yes | - | - | Yes | Yes |
| Spring Boot | Yes | - | Yes | Yes | - | - |
| CDI/Jakarta EE | - | - | Yes | - | - | - |
| Cucumber/BDD | - | - | Yes | - | - | - |
*DSL: Database Rider supports @DataSet and @ExpectedDataSet annotations. DB Tester uses the same annotation names. For Spock with Database Rider, use the RiderDSL programmatic API.
Analysis:
- DB Tester offers the only native JUnit 6 and Kotest support.
- Database Rider covers the widest test framework range for JUnit 5, but Spock requires a programmatic API.
- DBUnit lacks JUnit 5/6 support.
Data Format Support
| Format | DB Tester | DBUnit | Database Rider | Spring Test DBUnit | DbSetup | JDBDT |
|---|---|---|---|---|---|---|
| CSV | Yes | Yes | Yes | Yes | - | Yes |
| TSV | Yes | - | - | - | - | - |
| Flat XML | - | Yes | Yes | Yes | - | - |
| Full XML | - | Yes | Yes | Yes | - | - |
| YAML | - | - | Yes | - | - | - |
| JSON | - | - | Yes | - | - | - |
| Excel (XLS/XLSX) | - | Yes | Yes | Yes | - | - |
| Java DSL | - | - | Yes | - | Yes | Yes |
| Kotlin DSL | - | - | - | - | Yes | - |
| SQL Scripts | - | - | Yes | - | Yes | - |
Analysis:
- Database Rider supports the most formats (YAML, JSON, XML, CSV, Excel).
- DB Tester focuses on CSV/TSV for data management.
- DbSetup and JDBDT prefer programmatic data definition.
Configuration Approach
| Approach | DB Tester | DBUnit | Database Rider | Spring Test DBUnit | DbSetup | JDBDT |
|---|---|---|---|---|---|---|
| Annotations | Yes | - | Yes | Yes | - | - |
| Convention-based | Yes | - | - | - | - | - |
| Programmatic API | Yes | Yes | Yes | Yes | Yes | Yes |
| External Config (YAML/XML) | - | Yes | Yes | Yes | - | - |
| Global Defaults | Yes | - | Yes | Yes | - | - |
Convention-based Discovery (DB Tester unique):
src/test/resources/
└── com/example/UserRepositoryTest/ ← Matches test class
├── users.csv ← Table name
└── expected/
└── users.csv ← Expected stateDatabase Operations
| Operation | DB Tester | DBUnit | Database Rider | Spring Test DBUnit | DbSetup | JDBDT |
|---|---|---|---|---|---|---|
| NONE | Yes | Yes | Yes | Yes | - | - |
| INSERT | Yes | Yes | Yes | Yes | Yes | Yes |
| UPDATE | Yes | Yes | Yes | Yes | - | - |
| UPSERT | Yes | Yes | Yes | Yes | - | - |
| DELETE | Yes | Yes | Yes | Yes | Yes | Yes |
| DELETE_ALL | Yes | Yes | Yes | Yes | Yes | - |
| TRUNCATE_TABLE | Yes | Yes | Yes | Yes | Yes | - |
| CLEAN_INSERT | Yes | Yes | Yes | Yes | Yes | Yes |
| TRUNCATE_INSERT | Yes | Yes | Yes | Yes | - | - |
Assertion Capabilities
| Feature | DB Tester | DBUnit | Database Rider | Spring Test DBUnit | DbSetup | JDBDT |
|---|---|---|---|---|---|---|
| Full State Verification | Yes | Yes | Yes | Yes | - | Yes |
| Delta Assertions | - | - | - | - | - | Yes |
| Column Exclusion | Yes | Yes | Yes | Yes | - | Yes |
| Row Ordering Control | Yes | Yes | Yes | Yes | - | Yes |
| Regex Matching | Yes | - | Yes | - | - | - |
| Scriptable Expected Values | - | - | Yes | - | - | - |
| Scenario Filtering | Yes | - | - | - | - | - |
| Structured Error Output | Yes (YAML) | - | - | - | - | - |
Delta Assertions (JDBDT unique):
// Verify only inserted rows, ignore unchanged data
assertInserted(expected);
// Verify query had no side effects
assertUnchanged(dataSource);Scenario Filtering (DB Tester unique):
[Scenario],id,name,email
shouldCreateUser,1,john,john@example.com
shouldUpdateUser,1,john,john.updated@example.comAdvanced Features
| Feature | DB Tester | DBUnit | Database Rider | Spring Test DBUnit | DbSetup | JDBDT |
|---|---|---|---|---|---|---|
| Multiple DataSources | Yes | Yes | Yes | Yes | Yes | Yes |
| Transaction Support | Yes | Yes | Yes | Yes | Yes | - |
| FK Constraint Handling | Yes | Yes | Yes | Yes | Yes | - |
| Sequence/Identity Reset | - | Yes | Yes | Yes | - | - |
| Dataset Export | - | Yes | Yes | - | - | Yes |
| Replacement/Placeholder | - | Yes | Yes | - | - | - |
| Scriptable Datasets | - | - | Yes | - | - | - |
| Connection Leak Detection | - | - | Yes | - | - | - |
| SPI Extensibility | Yes | - | - | - | - | - |
| Logging/Diagnostics | Yes | Yes | Yes | Yes | - | Yes |
Scriptable Datasets (Database Rider):
USER:
- ID: 1
NAME: "js:(new Date()).toString()"
CREATED_AT: "groovy:new Date()"SPI Extensibility (DB Tester):
- Custom
TableSetLoaderProviderimplementations - Custom
OperationProviderimplementations - Custom
ExpectedDataSetProviderimplementations
DB Tester Limitations
Data Format Limitations
| Limitation | Impact | Workaround |
|---|---|---|
| No YAML/JSON support | Cannot use human-friendly formats for complex nested data | Use CSV with clear column naming |
| No XML support | Cannot migrate from existing DBUnit XML datasets | Convert XML to CSV manually or via script |
| No Excel support | Business users cannot maintain test data in spreadsheets | Export Excel to CSV |
| No programmatic dataset builder | Cannot generate dynamic test data in code | Implement custom DataLoader via SPI |
Feature Limitations
| Limitation | Impact | Alternative |
|---|---|---|
| No delta assertions | Cannot verify only the changes made by test | Verify full expected state |
| No scriptable datasets | Cannot embed dynamic values in CSV | Prepare data programmatically before each test | | No dataset export | Cannot capture current DB state for debugging | Use database client tools | | No replacement/placeholder | Cannot use variables in datasets | Define explicit values per scenario | | No sequence reset | Cannot reset auto-increment counters | Handle via SQL in @BeforeEach | | No connection leak detection | Connection leaks may go unnoticed | Use external monitoring tools |
Ecosystem Limitations
| Limitation | Impact | Consideration |
|---|---|---|
| No JUnit 4/5 support | Cannot use with legacy test suites | Migrate to JUnit 6 or use Database Rider |
| No TestNG support | Limited options for TestNG users | Use DbSetup or JDBDT |
| No CDI integration | Cannot auto-inject in Jakarta EE | Register DataSource manually |
| No Cucumber support | Cannot use in BDD scenarios | Use Database Rider for BDD |
| New project | Smaller community, less battle-tested | Evaluate thoroughly before production use |
| Limited documentation | Fewer examples and tutorials | Refer to test cases in source code |
When NOT to Choose DB Tester
Consider alternatives if you need:
- Multiple data formats → Choose Database Rider
- Existing XML datasets → Choose DBUnit or Database Rider
- BDD/Cucumber integration → Choose Database Rider
- JUnit 4/5 or TestNG → Choose DBUnit, Database Rider, or DbSetup
- Delta assertions → Choose JDBDT
- Code-only approach → Choose DbSetup
- Mature, battle-tested solution → Choose DBUnit
Framework Deep Dive
DB Tester
Philosophy: Convention over configuration with minimal boilerplate.
Unique Strengths:
- Zero-configuration dataset discovery based on test class and method names
- Scenario filtering shares datasets across multiple test methods
- YAML-formatted assertion errors provide readable debugging output
- Native Kotest support (only framework with this feature)
- SPI enables custom extensions
Architecture:
db-tester-api → Public annotations and interfaces
db-tester-core → JDBC implementation (internal)
db-tester-junit → JUnit 6 extension
db-tester-spock → Spock 2 extension
db-tester-kotest → Kotest 6 extensionExample:
@ExtendWith(DatabaseTestExtension.class)
@DataSet // Loads com/example/UserTest/users.csv
@ExpectedDataSet // Verifies against com/example/UserTest/expected/users.csv
class UserTest {
@Test
void shouldCreateUser() {
// [Scenario] column filters rows for this method
repository.create(new User("john", "john@example.com"));
}
}DBUnit
Philosophy: Comprehensive database state management with extensive customization options.
Unique Strengths:
- Most mature and battle-tested framework (since 2002)
- Extensive XML dataset support with schema validation
- ReplacementDataSet supports dynamic placeholders
- Database export captures production-like data
- Wide IDE and tool integration
Core Components:
IDatabaseConnection- Database connection abstractionIDataSet- Collection of tables (FlatXml, Xml, Xls, Query, and others)DatabaseOperation- CRUD operations on datasets
Example:
@Before
public void setUp() throws Exception {
IDatabaseConnection connection = new DatabaseConnection(dataSource.getConnection());
IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File("dataset.xml"));
DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
}Database Rider
Philosophy: Comprehensive DBUnit wrapper with annotation-driven API.
Unique Strengths:
- Widest data format support (YAML, JSON, XML, CSV, Excel)
- Scriptable datasets use Groovy/JavaScript
- Regex matching in expected datasets
- CDI and Cucumber integration
- Connection leak detection
- Active development and active community
Configuration Options:
@DataSet(
value = "users.yml",
strategy = SeedStrategy.CLEAN_INSERT,
cleanBefore = true,
cleanAfter = true,
disableConstraints = true,
transactional = true,
executeStatementsBefore = "SET FOREIGN_KEY_CHECKS=0",
executeStatementsAfter = "SET FOREIGN_KEY_CHECKS=1"
)Example:
@ExtendWith(DBUnitExtension.class)
class UserTest {
@Test
@DataSet("users.yml")
@ExpectedDataSet(value = "expected.yml", ignoreCols = {"id", "created_at"})
void shouldUpdateUser() {
repository.update(1L, new User("john.doe"));
}
}Spring Test DBUnit
Philosophy: Seamless Spring integration for DBUnit.
Unique Strengths:
- Deep Spring TestContext integration
- Transaction management integrates with Spring
- Familiar annotation style for Spring developers
- TestExecutionListener-based approach
Limitations:
- No active maintenance (last release 2016)
- No JUnit 5 support
- Spring-only
Example:
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class
})
@DatabaseSetup("/initial-data.xml")
@ExpectedDatabase("/expected-data.xml")
public class UserRepositoryTest {
@Test
public void shouldUpdateUser() { ... }
}DbSetup
Philosophy: Pure code, no external files, fast execution.
Unique Strengths:
- Zero external dependencies
- Type-safe Java/Kotlin DSL
- DbSetupTracker optimizes test execution
- Value generators handle sequences
- Fast execution
Limitations:
- Setup only, no assertion capabilities
- No annotation support
- Requires more boilerplate code
Example:
private static final Operation DELETE_ALL = deleteAllFrom("users", "orders");
private static final Operation INSERT_REFERENCE_DATA = sequenceOf(
insertInto("users")
.columns("id", "name", "email")
.values(1L, "john", "john@example.com")
.values(2L, "jane", "jane@example.com")
.build()
);
@BeforeEach
void prepare() {
new DbSetup(destination, sequenceOf(DELETE_ALL, INSERT_REFERENCE_DATA)).launch();
}Kotlin DSL:
val operation = dbSetup(to = destination) {
deleteAllFrom("users")
insertInto("users") {
columns("id", "name", "email")
values(1L, "john", "john@example.com")
}
}
operation.launch()JDBDT
Philosophy: Lightweight delta testing without external dependencies.
Unique Strengths:
- Delta assertions verify only changes
- Self-contained (Java 8 SE only)
- Programmatic dataset builders
- CSV import/export support
- Lightweight (~100KB)
Delta Assertion Concept:
Initial State (Snapshot) → Test Execution → Final State
↓
δ = Final - Initial
↓
Assert: δ matches expected changesExample:
@Before
public void setup() {
// Take snapshot of initial state
snapshot = takeSnapshot(userTable);
}
@Test
public void testInsertUser() {
// Execute code under test
repository.insert(new User("john"));
// Assert only the delta (inserted rows)
assertInserted(
data(userTable)
.row("john", "john@example.com")
);
}
@Test
public void testQueryDoesNotModify() {
repository.findAll();
// Assert no changes were made
assertUnchanged(userTable);
}Decision Matrix
By Use Case
| Use Case | Recommended | Alternatives |
|---|---|---|
| New JUnit 6 project | DB Tester | - |
| JUnit 5 project | Database Rider | DbSetup, JDBDT |
| Spock/Groovy project | DB Tester | DbSetup |
| Kotest/Kotlin project | DB Tester | DbSetup (Kotlin DSL) |
| Legacy JUnit 4/5 project | Database Rider | DBUnit |
| Spring Boot application | DB Tester, Database Rider | Spring Test DBUnit |
| Jakarta EE / CDI | Database Rider | - |
| BDD / Cucumber | Database Rider | - |
| Minimal dependencies | DbSetup, JDBDT | DB Tester |
| Change verification only | JDBDT | - |
| Extensive format flexibility | Database Rider | DBUnit |
By Team Preference
| Preference | Recommended |
|---|---|
| Convention over configuration | DB Tester |
| Annotation-driven | DB Tester, Database Rider |
| Code-only (no external files) | DbSetup, JDBDT |
| YAML/JSON datasets | Database Rider |
| Battle-tested solution | DBUnit, Database Rider |
| Lightweight | DbSetup, JDBDT, DB Tester |
Migration Guides
From Database Rider to DB Tester
| Database Rider | DB Tester | Notes |
|---|---|---|
@DataSet("users.yml") | @DataSet | Convert YAML to CSV |
@ExpectedDataSet("expected.yml") | @ExpectedDataSet | Convert YAML to CSV |
strategy = SeedStrategy.CLEAN_INSERT | operation = Operation.CLEAN_INSERT | Same semantics |
ignoreCols = {"id"} | excludeColumns = {"id"} | Same functionality |
cleanBefore = true | Default behavior | CLEAN_INSERT is default |
dbunit.yml config | @DatabaseTestConfiguration | Annotation-based |
From Spring Test DBUnit to DB Tester
| Spring Test DBUnit | DB Tester | Notes |
|---|---|---|
@DatabaseSetup("/data.xml") | @DataSet | Convert XML to CSV |
@ExpectedDatabase("/expected.xml") | @ExpectedDataSet | Convert XML to CSV |
DbUnitTestExecutionListener | DatabaseTestExtension | JUnit 6 extension |
@DbUnitConfiguration | @DatabaseTestConfiguration | Similar options |
From DbSetup to DB Tester
| DbSetup | DB Tester | Notes |
|---|---|---|
insertInto("users").columns(...).values(...) | users.csv file | Externalize to file |
deleteAllFrom("users") | Implicit in CLEAN_INSERT | Default behavior |
DbSetupTracker | Not needed | Each test has own data |
| No assertions | @ExpectedDataSet | Add verification |
References
Official Documentation
Related Tools
- Testcontainers - Database containers for integration testing
- Flyway - Database migration tool
- Liquibase - Database change management