skip to content

What is @JdbcTest and what does it auto-configure for a test?

level: juniorimportance: must knowfreq 55%

answer

  1. Slice = only JDBC beans
  2. JdbcTemplate + embedded H2/HSQL/Derby
  3. Transactional -> rollback per test
  4. No @Repository/@Service scan -> @Import
  5. Replace.ANY by default

basics

~10 s

@JdbcTest is a Spring Boot test slice for plain JDBC/JdbcTemplate code. It loads only JDBC beans plus an in-memory database, wraps each test in a rolled-back transaction, and skips the rest of the app.

solid answer

~40 s

@JdbcTest is a Spring Boot 'test slice' focused on plain-JDBC persistence. Instead of starting the whole application context, it loads only JDBC infrastructure: a DataSource, JdbcTemplate, and NamedParameterJdbcTemplate. By default it replaces any real DataSource with an in-memory embedded database (H2/HSQL/Derby if on the classpath), so you need one of those on the test classpath. Each test method runs inside a transaction that is rolled back at the end, so tests stay isolated with no data leakage. It deliberately does NOT scan your @Service/@Component/@Repository beans and does not configure JPA, so it is far faster than @SpringBootTest. You bring the class under test in with @Import or a nested @TestConfiguration. Use it to test SQL statements and row-mapping logic against a lightweight DB.

code

java · 21 lines
java
@JdbcTest
@Import(EmployeeRepository.class) // slice does not scan your beans; bring it in
class EmployeeRepositoryTest {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private EmployeeRepository repository; // uses JdbcTemplate under the hood

    @Test
    void savesAndFindsByName() {
        jdbcTemplate.execute(
            "CREATE TABLE employee (id IDENTITY, name VARCHAR)");

        repository.save(new Employee("Ada"));

        assertThat(repository.findByName("Ada")).isPresent();
    }
    // transaction is rolled back automatically after the test
}

go deeper

for a junior

Know it is a slice for JdbcTemplate tests with an in-memory DB and per-test rollback.

for a middle

Explain Replace.ANY vs Replace.NONE, why you must @Import your repository, and the embedded-DB dependency requirement.

for a senior

Contrast @JdbcTest vs @DataJpaTest vs @DataJdbcTest and discuss H2-vs-prod SQL drift and Testcontainers.

for a principal

Weigh slice speed/isolation against fidelity, drive a team convention on embedded-vs-real DB, and reason about transaction-rollback semantics interacting with connection-per-test behavior.

## What it is `@JdbcTest` is a **test slice** annotation from Spring Boot (`org.springframework.boot.test.autoconfigure.jdbc.JdbcTest`). A 'slice' means that instead of starting your *entire* application context the way `@SpringBootTest` does, Spring Boot loads only a narrow, curated set of auto-configurations relevant to one layer — here the **plain JDBC** layer (`JdbcTemplate`), *not* JPA/Hibernate. ## What it auto-configures Annotating a test class with `@JdbcTest` wires up: - a **`DataSource`** (the DB handle / connection pool), - a **`JdbcTemplate`** and a **`NamedParameterJdbcTemplate`** (the classic low-level Spring JDBC helpers), - Spring's **`DataSourceTransactionManager`** plus test transaction management. It is meta-annotated with `@Transactional`, so **every test method runs in a transaction that is rolled back** when the method finishes. That keeps tests independent — inserts in one test never leak into the next. ## The embedded database By default `@JdbcTest` is combined with `@AutoConfigureTestDatabase`, whose default policy is `Replace.ANY`: it **replaces whatever `DataSource` your app defines with an auto-configured in-memory embedded DB**. Spring Boot picks an embedded engine from the classpath — **H2**, **HSQLDB**, or **Apache Derby**. If none of those is present the test fails to start, because there is no embedded engine to substitute. To run against your real/configured datasource instead, use `@AutoConfigureTestDatabase(replace = Replace.NONE)`. ## What it does NOT load Slices are deliberately minimal. `@JdbcTest` does **not** component-scan your `@Service`, `@Component`, or `@Repository` beans, does **not** configure JPA/`EntityManager`, and does **not** start the web layer. If your repository is a hand-written class using `JdbcTemplate`, register it explicitly with `@Import(MyRepository.class)` or a nested `@TestConfiguration`. Schema/seed data: put a `schema.sql`/`data.sql` on the classpath, use a Testcontainers/Flyway/Liquibase-driven DB with `Replace.NONE`, or `@Sql` scripts. ## When to use it Reach for `@JdbcTest` when you have plain-JDBC repositories (raw SQL + `RowMapper`) and want to verify the SQL and mapping against a database — fast, isolated, no full context. If you use Spring Data JPA repositories instead, the sibling slice `@DataJpaTest` is the right tool; for Spring Data JDBC there is `@DataJdbcTest`. ## Common gotchas - Forgetting an embedded-DB dependency → context fails to start. - Expecting your `@Repository`/`@Service` beans to be present — they are not; import them. - Assuming data persists across tests — it is rolled back every method. - Testing against H2 while production is PostgreSQL: dialect/SQL differences can hide bugs (see `Replace.NONE` + Testcontainers).

  • Your @JdbcTest fails at startup with 'Failed to replace DataSource with an embedded database'. Why?
    No embedded database engine (H2/HSQLDB/Derby) is on the test classpath. The default @AutoConfigureTestDatabase(replace = Replace.ANY) needs one to substitute; add an embedded DB dependency, or use replace = Replace.NONE to keep your configured datasource.
  • How do you make @JdbcTest run against your real PostgreSQL instead of H2?
    Annotate with @AutoConfigureTestDatabase(replace = Replace.NONE) so Spring keeps the configured DataSource, and point it at a real DB — typically a Testcontainers PostgreSQL container to keep tests hermetic.

saying these in an interview costs you the question

  • Thinking @JdbcTest loads @Service/@Repository beans automatically (it does not).
  • Believing it configures JPA/EntityManager (that is @DataJpaTest).
  • Assuming inserted rows persist across test methods (each is rolled back).
  • Thinking it starts the full application context like @SpringBootTest.

context