Spring Boot
DataJpaTest
H2 Database
Embedded Database
Schema Generation

Spring Boot. DataJpaTest H2 embedded database create schema

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

@DataJpaTest is designed to load a narrow Spring test slice focused on JPA repositories, and it commonly pairs with an embedded H2 database. The usual question is not whether H2 works, but how the schema gets created for the test. In practice, Spring Boot can create that schema from JPA entity metadata, from SQL scripts, or from migration tools, and the test should choose one path deliberately.

What @DataJpaTest Sets Up

A minimal repository test often looks like this:

java
1import org.junit.jupiter.api.Test;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
4
5@DataJpaTest
6class UserRepositoryTest {
7
8    @Autowired
9    private UserRepository userRepository;
10
11    @Test
12    void repositoryLoads() {
13        System.out.println(userRepository.count());
14    }
15}

By default, @DataJpaTest configures repository infrastructure and commonly replaces the normal datasource with an embedded test database if one is available.

Schema from JPA Entities

If you want Hibernate to create the schema directly from the entity mappings, set the DDL mode accordingly.

properties
spring.jpa.hibernate.ddl-auto=create-drop

With H2, this is often enough for repository tests. Spring Boot starts the in-memory database, Hibernate inspects the entities, creates the tables, and drops them again when the test context closes.

This is the easiest path when:

  • the entity mappings are the source of truth
  • you do not need vendor-specific SQL behavior
  • you want fast isolated repository tests

Schema from SQL Scripts

Sometimes the test schema should come from SQL files instead of generated DDL. In that case, place scripts such as schema.sql and optionally data.sql in the test resources and make sure SQL initialization is enabled when needed.

properties
spring.sql.init.mode=always

Example schema.sql:

sql
1CREATE TABLE users (
2    id BIGINT PRIMARY KEY,
3    username VARCHAR(255) NOT NULL
4);

This is useful when the test must mirror a specific schema shape instead of whatever Hibernate currently derives from the entities.

Avoid Mixing Competing Schema Strategies by Accident

A frequent source of confusion is enabling multiple schema-creation paths at once, for example:

  • 'ddl-auto=create-drop'
  • 'schema.sql'
  • Flyway or Liquibase migrations

If more than one mechanism is active, you can get duplicate creation attempts or test behavior that is hard to reason about. Repository tests are much easier to maintain when one schema source is chosen explicitly.

Control Whether the Test Uses H2 or the Real Database Type

By default, @DataJpaTest often swaps in an embedded test database. If that is not what you want, disable the replacement.

java
1import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
2import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
3import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
4
5@DataJpaTest
6@AutoConfigureTestDatabase(replace = Replace.NONE)
7class UserRepositoryTest {
8}

This is useful when the repository logic depends on behavior that H2 does not model well enough compared with the production database.

Use Test Properties to Keep the Setup Explicit

A test-specific properties file often makes the setup clearer.

properties
1spring.datasource.url=jdbc:h2:mem:testdb
2spring.datasource.driver-class-name=org.h2.Driver
3spring.datasource.username=sa
4spring.datasource.password=
5spring.jpa.hibernate.ddl-auto=create-drop

This gives the test slice a predictable database and makes the schema strategy visible in one place.

Know What You Are Actually Testing

If the goal is repository logic and JPA mappings, generated schema in H2 is often enough. If the goal is to validate exact DDL, SQL dialect, indexes, or migration scripts, an in-memory H2 database may not be representative enough.

That is the main architectural question behind many @DataJpaTest problems: do you want a fast repository test or a database-faithful integration test? Those are related but different goals.

Common Pitfalls

  • Assuming @DataJpaTest always creates the schema automatically without checking the configured strategy.
  • Enabling both Hibernate DDL generation and SQL scripts without intending to.
  • Forgetting that H2 may not behave exactly like the production database dialect.
  • Letting the embedded test database replace the real datasource when the test needed the production database type.
  • Treating schema generation and test data loading as if they were the same configuration problem.

Summary

  • '@DataJpaTest commonly works with H2 for fast repository-focused tests.'
  • The schema can be created from JPA entities, SQL scripts, or migration tools.
  • 'spring.jpa.hibernate.ddl-auto=create-drop is the usual generated-schema choice.'
  • Pick one schema-creation path deliberately instead of mixing several.
  • If dialect fidelity matters more than speed, H2 may not be the right test database.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.