Start Learning
Javaneer
Back to stage
Module 5·Testing Spring Applications

Data Slice Tests with @DataJpaTest

Test repositories and queries against a real (test) database, with the rest of the app left out.

14 min readIntermediate
On this page

Your repositories carry real logic - derived queries, JPQL, JOIN FETCH. A mock can't tell you whether findByAuthorIgnoreCaseOrderByTitleAsc actually returns the right rows in the right order; only a database can. @DataJpaTest starts just the JPA layer against a test database so you can verify queries for real, fast.

The slice

@DataJpaTest configures JPA, Hibernate, and your repositories - and nothing else (no web layer, no services, no security). It gives each test a fresh, isolated database and rolls back after every test, so tests never pollute each other.

@DataJpaTest
class BookRepositoryTest {

    @Autowired BookRepository repository;

    @Test
    void findsBooksByAuthorSortedByTitle() {
        repository.save(new Book("978-1", "Zebra", "Bloch", 1));
        repository.save(new Book("978-2", "Apple", "Bloch", 1));
        repository.save(new Book("978-3", "Other", "Gosling", 1));

        var books = repository.findByAuthorIgnoreCaseOrderByTitleAsc("bloch");

        assertThat(books).extracting(Book::getTitle).containsExactly("Apple", "Zebra");
    }
}

You saved real rows and ran a real query - the assertion proves the derived method's WHERE, ORDER BY, and case-insensitivity all work.

Each test starts clean and rolls back

@DataJpaTest wraps each test in a transaction that's rolled back at the end, so tests are isolated and repeatable - you never have to clean up data between them.

H2 now, the real engine later

By default @DataJpaTest uses an embedded database (H2). That's fast and fine for straightforward queries, but H2 isn't PostgreSQL - a native query or a database-specific feature can pass on H2 and fail in production. That gap is exactly what Testcontainers (next lesson) closes, by pointing the same slice at a real PostgreSQL container.

Test the plumbing with water, not a diagram

You can't verify a building's plumbing by reading the blueprint - you have to turn the water on and watch it flow through the actual pipes. Mocking a repository tests the blueprint; @DataJpaTest turns the water on. It runs your queries through a real JPA provider and a real (if lightweight) database, so you find leaks the diagram can't show.

What can only @DataJpaTest catch?

BookVault's LoanRepository.findActiveByMember uses a JPQL JOIN FETCH to load each loan's book and member. Why can a plain unit test with a mocked repository never verify this method works, and what would a @DataJpaTest prove that a mock cannot?

What does @DataJpaTest load and test?

Key takeaways

  • @DataJpaTest starts only the JPA layer and repositories against a test database - no web, service, or security.
  • It runs real queries against real rows, so it verifies derived methods, JPQL, ordering, and mappings a mock never could.
  • Each test is wrapped in a transaction and rolled back, keeping tests isolated and repeatable.
  • By default it uses embedded H2; database-specific behavior may differ from production.
  • Point the same slice at a real engine with Testcontainers to close the H2-vs-production gap.
Was this lesson helpful?
Edit this page on GitHub