persistence-test

Catch N+1 queries, query-count drift, and missing indexes in Spring Boot integration tests - by capturing SQL at the JDBC layer, not by parsing Hibernate logs.

CI status Coverage Status License

The problem

An integration test can pass while quietly issuing ten times the queries it used to - an N+1 that crept in, an index that got dropped, a fetch join that stopped working. Nothing fails, nothing warns; the regression just ships. Parsing Hibernate's SQL logs to catch this is fragile and framework-specific.

What it does

Captures

Wraps the DataSource at the JDBC layer, so every statement is recorded regardless of whether it came from Spring Data JPA, Hibernate, JdbcTemplate, or plain JDBC.

Asserts

A fluent assertThatQueries() AssertJ DSL for counts, tables, duplicates, and N+1 detection, plus PostgreSQL EXPLAIN-backed index assertions.

Stays out of the way

Test-scoped dependencies, automatic DataSource wrapping under Spring Boot, no annotation processor.

Usage

Add the dependencies (see latest release for the version):

<dependency>
    <groupId>li.selman</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>VERSION</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>li.selman</groupId>
    <artifactId>query-assertions</artifactId>
    <version>VERSION</version>
    <scope>test</scope>
</dependency>
@SpringBootTest
class OrderRepositoryTest {

    @Autowired
    private OrderRepository orderRepository;

    @Test
    void findsOrdersByCustomerWithoutNPlusOne() {
        orderRepository.findByCustomerId(customerId);

        assertThatQueries().selects(1).containsNoDelete().hasNoNPlusOne();
    }
}

No manual DataSource wrapping and no @ExtendWith needed - the DataSource bean is wrapped automatically, and capture state resets before every test method. Full module breakdown, including hibernate-support, snapshot-testing, and plan-assertions, is in the README.

Modules

ModulePurpose
persistence-test-coreDomain model + SQL normalization, no framework dependencies.
query-captureJDBC-layer capture via datasource-proxy.
query-analysisStatistics, duplicate/N+1 detection.
query-assertionsThe assertThatQueries() AssertJ DSL.
hibernate-supportEntity-aware assertions (optional Hibernate dependency).
snapshot-testingDeterministic query snapshots via java-snapshot-testing.
spring-boot-autoconfigureAutomatic DataSource wrapping + test wiring.
plan-assertionsPostgreSQL EXPLAIN-backed index/scan assertions.