Library / SDK
quick-perf/quickperf avatar
quick-perf/quickperf

QuickPerf: performance properties as test assertions

QuickPerf is a testing library for Java to quickly evaluate and improve some performance-related properties

542 stars74 forksJavaApache-2.0

At a glance

What is it?
QuickPerf is a Java testing library that lets you write performance expectations the way you write functional ones. Annotate a test with the property you care about, and the build fails when it is violated, which is how the library detects an N+1 select problem in a repository test or an allocation budget that has quietly grown by a hundred megabytes.
Who is it for?
QuickPerf suits a Java team that has been caught by an N+1 query or an allocation regression and wants a build that fails rather than a postmortem, and it suits teams whose test suite already runs on every commit.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A testing library for performance-related properties

QuickPerf is a testing library for Java to quickly evaluate and improve some performance-related properties, and that sentence is the whole pitch.

The project is on Maven Central under the org.quickperf group, it is Apache-2.0 licensed, and the repository carries the badges you would expect for a library published to a central repository: the Maven Central version badge, a reproducible builds badge pointing at the reproducible-central project, the licence badge and a CI badge for the CI workflow.

The documentation lives in a separate repository, the quick-perf/doc wiki, and the project site is quickperf.io. The README links the wiki pages for the annotation scopes, the frameworks and test frameworks, and the frequently asked questions.

The annotation scopes are the organising idea of the library, and there are three at the top level: core annotations, JVM annotations and SQL annotations, with more linked from the wiki.

The JVM scope covers properties of the runtime itself, the SQL scope covers what the application sends to the database, and the core scope holds the mechanism. Each scope is a separate concern with its own documentation page, which is a sensible structure for a library that spans from allocation measurement to query counting.

The maintenance picture is mixed and worth noting up front. The tagged releases are release-1.0.0 in November 2020, release-1.0.1 in December 2020 and release-1.1.0 in September 2021, while the last push to the repository was on 2026-10-20. So the code is still being worked on, several years after the last published version. The topics list is long and specific, covering allocation, hibernate, java-flight-recorder, java-flight-recordings, jdbc, jvm, microservice, microservices, n-plus-1, orm, spring, spring-boot, spring-data-jpa and sql, which describes the range the library covers.

Performance expectations written like functional ones

The JVM annotation example in the README is the clearest statement of the design, and it is short.

java
    @MeasureHeapAllocation
    @HeapSize(value = 1, unit = AllocationUnit.GIGA_BYTE)
    @Test
    public void execute_batch() {
        ...
    }

The reading of that is straightforward. The test measures heap allocation, and the expectation is that it stays under one gigabyte. If the code under test starts allocating more, the test fails.

That is the whole idea, and it is worth contrasting with the usual approach. Normally a performance problem is found by profiling, by watching a dashboard, or by a customer reporting that the application got slow. QuickPerf turns the same kind of knowledge into an assertion, and assertions are what a build system understands: the build goes red, the commit does not land, and the regression is caught while the person who wrote it is still there.

The annotations are applied to the test method, so they are inherited by whatever test framework runs it. The library ships modules for JUnit 4, JUnit 5 and TestNG, plus a Spring module, and the README links the wiki pages for each.

The examples for the JVM annotations are in the quickperf-examples repository, with separate directories for JUnit 4, JUnit 5 and TestNG, so the same annotation is shown in all three frameworks. There is also a separate project, maven-test-bench, that measures the heap allocation of Apache Maven itself, which is a good illustration of the scale the library is meant to handle.

The N+1 detector, and what the failure message tells you

The SQL annotations are the part of QuickPerf that has the most immediate value for a Spring or Hibernate codebase, and the README shows both the annotation and the failure output.

java
    @ExpectSelect(1)
    @Test
    public void should_find_all_players() {
     ...
    }

The test expects exactly one select statement. When the code under test issues more, the failure message explains what happened in plain language: you may think that one select statement was sent to the database, but there are in fact ten. And then the warning that you may have even more select statements with production data, with a link to a post on the cost of JDBC server roundtrips.

That link is the point of the message. An N+1 query is not slow because there are ten queries, it is slow because each query is a network round trip to the database server, and the cost of that round trip dominates everything else about the query. A failure message that links the explanation is doing something a plain assertion cannot.

The library also auto-detects the frameworks involved. With Hibernate, the failure suggests the usual remedies: a join fetch, a left join fetch, a lazy fetch type, and so on. With Spring Data JPA, it suggests adding an entity graph with attribute paths on the repository method, and links the Spring Data JPA reference documentation.

So the failure is not just a red test. It names the pattern, it names the framework you are using, and it names the specific annotation or fetch type that fixes it. That is a much more useful artefact than a count.

The module layout, and the frameworks it plugs into

The repository is a Maven multi-module project, and the directory names are the module names.

There is core/, which is the shared mechanism, then jvm/ for the runtime properties and sql/ for the database ones. Then the integration modules: junit4/, junit5/ and testng/ for the test frameworks, and spring/ for the Spring integration. There is also bom/, a bill of materials, which is how a project with a dozen published artefacts keeps their versions aligned for consumers.

The build is driven by pom.xml at the root with the Maven wrapper, mvnw and mvnw.cmd, and a .mvn/ directory holding the wrapper configuration, so a contributor does not need Maven installed.

There is also a licences/ directory, an update-licence-header.txt script, a CODE_OF_CONDUCT.md and a CONTRIBUTING.md. The licence header script is a detail worth noting: it keeps the Apache headers consistent across the source tree, which matters in a project with a lot of files and a mix of contributors.

The scope of the library is visible in the topic list as well as the module list. Beyond allocation and SQL, the topics name hibernate, spring-data-jpa, jdbc, orm, jvm and java-flight-recorder, which tells you the library reaches from the test method into the ORM layer and towards the flight recorder for deeper analysis of the same run.

For the framework support, the README links separate wiki pages for Spring, JUnit 4, JUnit 5 and TestNG, and the examples repository has matching example directories, including springboot-junit4 and springboot-junit5, so the Spring Boot integration is demonstrated in both the older and the newer test framework.

Talks in two languages and a small core team

The README's contributor section is a plain list of names with what each of them contributed, and the list tells you how the project is organised.

Jean Bisutti appears first, with links to commits for code, tests, documentation, design, examples, reviewed pull requests and talks, which is the profile of the person who has carried most of the project. Guillaume Raghoumandan is listed for code and tests, and Patrice Cavezzan appears in the truncated part of the list with the same kind of entries.

The talks section links two playlists, one in English and one in French, and the fact that there are two is a clue about where the project comes from and who it speaks to.

The documentation is the wiki in the separate quick-perf/doc repository, and the FAQ page is linked alongside the annotation and framework pages. There is no single long document, which is the shape a library with three annotation scopes and four test framework integrations tends to take: each topic gets a page, and the wiki is the index.

The project also asks for contributions in a friendly way, saying you are very welcome to contribute and that some relatively easy things can be done while other issues are more challenging, and the contributing guide is the place to start.

So the practical picture of the project is a small team, a wiki-driven documentation model, and a library that is still being worked on but whose published versions stopped in 2021.

Where QuickPerf is the wrong tool

There are clear cases where a performance assertion library is the wrong answer, and the reasons are about the kind of question being asked.

QuickPerf asserts, it does not explain. When the test fails you learn that a property was violated, and for the SQL annotations you also learn the pattern and the fix, but for the JVM ones you are told that allocation exceeded a threshold. Diagnosing why is a profiling job, and the profiler is a different tool with a different workflow, run outside the test suite on a representative workload.

It is also the wrong tool for measuring absolute performance. The thresholds are absolute numbers, and absolute numbers depend on the machine the test ran on. A build agent with a different processor or a different JVM will allocate differently, so a budget tuned on one machine either fails spuriously or is loose enough to catch nothing. QuickPerf is at its best on a stable environment where it catches a change rather than a level.

For microbenchmarking, where you want to compare two implementations of a method with proper statistics and warmup, a benchmarking harness designed for that is the correct instrument. QuickPerf measures the test method you already have, which is a different and, for regression detection, more valuable thing.

And for production behaviour, where the interesting questions are about real traffic and real data volumes, the answer is monitoring rather than a test-time assertion. The library belongs at the stage where a regression is cheap to catch, which is before the code reaches production, and not after.

The one case where it clearly wins is the N+1 query, because there the property is countable and the fix is known, so an assertion plus a diagnosis in the failure message is close to a complete answer.

Editorial conclusion

QuickPerf suits a Java team that has been caught by an N+1 query or an allocation regression and wants a build that fails rather than a postmortem, and it suits teams whose test suite already runs on every commit. It does not suit somebody looking for a profiler, since it asserts rather than explains, and it does not suit a project that wants to compare absolute performance between builds, because the properties are relative to the threshold you set on the machine that runs the tests. Check three things before you adopt it: which annotation scope covers the property you care about, since the core, JVM and SQL scopes are separate and the JVM ones need the right test framework module, that your test environment is stable enough for the measurement to be meaningful, since an allocation budget measured on a loaded build agent is noise, and how far the version you take is from the last release, because the tagged releases stop at 1.1.0 from 2021 while the repository itself was pushed to on 2026-10-20. The last push to the repository was on 2026-10-20 and the newest release is release-1.1.0.

Frequently asked questions

What is QuickPerf?

It is a testing library for Java to quickly evaluate and improve some performance-related properties. It is published on Maven Central under org.quickperf, licensed under Apache-2.0, and documented in a wiki in the separate quick-perf/doc repository.

How does QuickPerf detect an N+1 select problem?

You annotate the test with @ExpectSelect and the expected number of statements. When more selects are issued, the failure message says you may think one select was sent but there are in fact several, warns about the cost of JDBC roundtrips, and suggests the fix for the framework in use, such as a join fetch with Hibernate or an entity graph with Spring Data JPA.

Which test frameworks does QuickPerf support?

JUnit 4, JUnit 5 and TestNG, each with its own module and its own examples in the quickperf-examples repository, plus a Spring module and Spring Boot examples for both JUnit 4 and JUnit 5.

What annotation scopes does QuickPerf have?

The README links the core, JVM and SQL annotation scopes, with more scopes linked from the wiki. The JVM scope covers runtime properties such as heap allocation, the SQL scope covers the statements sent to the database, and the core scope holds the shared mechanism.

What are the recent QuickPerf releases?

The tagged releases are release-1.0.0 from 2020-11-18, release-1.0.1 from 2020-12-11 and release-1.1.0 from 2021-09-29, while the last push to the repository was on 2026-10-20, so the code has moved on since the last published version.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. quick-perf/quickperf on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/quick-perf-quickperf.svg)](https://hysenlabs.com/projects/quick-perf-quickperf)

Was this useful?