Skip to content

JDBScriptDatabase Test State Setup

Type-safe, zero-boilerplate database test fixtures for modern Java.

Why JDBScript? ​

Setting up and verifying relational database fixtures in Java tests has traditionally been painful and fragile. JDBScript bridges this gap:

  • Compile-Time Checking
    • Problem: Raw SQL strings and XML/JSON datasets fail at runtime when schemas change, offering zero compiler feedback or IDE safety.
    • Solution: Schemas are defined as typed Java interfaces. Renaming a column or changing a type triggers compile errors immediately.
  • No XML or Raw SQL
    • Problem: DbUnit-style XML datasets are tedious to maintain, difficult to refactor, and decouple data definitions from your code.
    • Solution: Construct test datasets using fluent Java syntax, full IDE autocomplete, reusable fixtures, and smart default generators.
  • Automatic FK-Ordering
    • Problem: Inserting or cleaning up dependent records requires manually managing topological order to avoid foreign key constraint violations.
    • Solution: JDBScript introspects foreign key metadata automatically, guaranteeing correct insertion order and safe reverse teardown.
  • Multi-DBMS Compatibility
    • Problem: Raw SQL fixtures and DB-specific tools break when running tests across different DBMSs (e.g., in-memory databases locally vs PostgreSQL/Oracle in CI).
    • Solution: A single unified Java fixture runs transparently across 12+ supported databases including PostgreSQL, MySQL, Oracle, SQL Server, SQLite, DuckDB, and H2 with automatic dialect and sequence handling.

JDBScript vs DbUnit ​

While DbUnit established dataset-driven testing in Java, maintaining external XML/YAML datasets imposes recurring maintenance overhead as applications evolve.

DimensionDbUnit DatasetsJDBScript
Schema DriftSilent failures at test runtimeImmediate compile errors in the IDE
RefactoringFragile text search across external filesAutomated IDE rename and reference updates
Fixture BoilerplateMust specify all non-null columns per rowSmart defaults generate IDs and non-essential columns
Type SafetyStringly-typed data; manual converters for Enums/UUIDsNative Java types, Enums, and automatic JDBC conversion
Sequence ManagementManual sequence reset scripts to avoid ID collisionsAutomatic sequence restarts preventing ID collisions

Quickstart ​

Add the jdbscript dependency to your project's test scope:

xml
<dependency>
    <groupId>org.jdbscript</groupId>
    <artifactId>jdbscript</artifactId>
    <version>1.3.0</version>
    <scope>test</scope>
</dependency>
kotlin
testImplementation("org.jdbscript:jdbscript:1.3.0")
groovy
testImplementation 'org.jdbscript:jdbscript:1.3.0'

Code Example ​

1. Declare Your Schema Interface ​

Define lightweight interfaces extending IDBSchema and IDBRecord to reflect your tables and columns:

java
import org.jdbscript.IDBSchema;
import org.jdbscript.IDBSchema.IDBRecord;

public interface IAppSchema extends IDBSchema {
    IUserRecord users();
    IOrderRecord orders();

    interface IUserRecord extends IDBRecord {
        IUserRecord id(Long id);
        IUserRecord username(String username);
        IUserRecord email(String email);
        IUserRecord active(Boolean active);
    }

    interface IOrderRecord extends IDBRecord {
        IOrderRecord id(Long id);
        IOrderRecord user_id(Long userId);
        IOrderRecord total_amount(Double amount);
    }
}

2. Seed and Reset Test State with resetDB ​

Initialize JDBEngine and wipe tables & insert fixtures in a single fluent call:

java
import org.jdbscript.JDBEngine;
import org.jdbscript.IJDBEngine;
import javax.sql.DataSource;

DataSource dataSource = getDataSource();
IJDBEngine<IAppSchema> engine = JDBEngine.builder(IAppSchema.class)
    .dataSource(dataSource)
    .build();

// Wipes schema tables and inserts records in FK-safe order
engine.resetDB(db -> {
    db.users().id(1L).username("alice").email("[email protected]").active(true);
    db.users().id(2L).username("bob").email("[email protected]").active(false);
    db.orders().id(1001L).user_id(1L).total_amount(59.99);
});

3. Verify Database State with assertDB ​

Assert that expected records exist or do not exist using the same intuitive syntax:

java
// Assert that records exist in the database
engine.assertDBHas(db -> {
    db.users().username("alice").active(true);
    db.orders().user_id(1L).total_amount(59.99);
});

// Assert that records do not exist
engine.assertDBHasNot(db -> {
    db.users().username("charlie");
});

Recipes ​

Runnable, self-contained example projects demonstrating real-world usage patterns across different stacks:

Frameworks & Ecosystem ​

Migration Testing ​

Core Patterns & Composition ​

Advanced Modeling ​

Released under the Apache 2.0 License.