Quarkus Testing
@QuarkusTest, dev services, mocking, and isolated test profiles.
# CLAUDE.md — Quarkus Testing
## Test types
- `@QuarkusTest` — full Quarkus app loaded. Use for integration-style tests of endpoints, services, and DB.
- `@QuarkusIntegrationTest` — runs against the packaged artifact (JVM jar or native binary). Use for smoke tests of the deployed bundle.
- Plain JUnit 5 — for pure logic that doesn't need Quarkus.
## Dev services
- Quarkus auto-starts containers (Postgres, Redis, Kafka, etc.) for tests when the right extensions are on the classpath.
- No `@Container`, no Testcontainers boilerplate — just add the extension and write the test.
- Override with explicit config when you need a specific image or version.
## REST testing
- Use **REST-assured** for endpoint tests:
```java
given().contentType(JSON).body(req)
.when().post("/users")
.then().statusCode(201).body("email", is("a@b"));
```
- `@TestHTTPEndpoint(UsersResource.class)` to skip repeating the path prefix.
- For reactive endpoints, REST-assured works the same — the reactive nature is server-side.
## Mocking
- `@InjectMock` to replace a CDI bean with a Mockito mock for one test class:
```java
@QuarkusTest
class UserServiceTest {
@Inject UserService service;
@InjectMock EmailGateway email;
}
```
- For full bean replacement (alternative implementation), use `@Alternative` + `@Priority`.
- Don't `@InjectMock` value types — mock services and gateways at the bean boundary.
## Test profiles
- `@TestProfile(MyProfile.class)` to override config per test class:
```java
static class MyProfile implements QuarkusTestProfile {
@Override public Map<String, String> getConfigOverrides() {
return Map.of("app.email.smtp-host", "test.example.com");
}
}
```
- A new app is started per profile. Group tests with the same profile to keep startup costs amortized.
## Database
- Each test gets a transaction that rolls back via `@TestTransaction`:
```java
@Test
@TestTransaction
void persists_user() { repository.persist(new User(...)); }
```
- For tests that need committed state (multi-thread, async), don't use `@TestTransaction` — clean up explicitly.
## Speed
- Quarkus reuses the application context across `@QuarkusTest` classes when configs match. Don't fragment with unique profiles unless necessary.
- Run unit tests first, integration tests later in CI. Fail fast.
- Continuous testing in dev mode (`r` in the dev console) re-runs only affected tests.
## Don't
- Don't use Spring's `@SpringBootTest` mental model in Quarkus. Quarkus tests are usually faster and need less setup.
- Don't `@InjectMock` infrastructure beans Quarkus controls (e.g., `EntityManager`). Use `@TestTransaction` and a real DB.
- Don't run native tests on every save. Save them for `mvn verify -Pnative` in CI.
- Don't share state across tests via static fields. Tests run in undefined order.
Other Java templates
Modern Java Rules
Java 21+ defaults: records, sealed types, pattern matching, virtual threads, var.
Java Testing with JUnit 5
JUnit 5 + AssertJ + Mockito + Testcontainers — opinionated test conventions.
Java Virtual Threads & Concurrency
Project Loom virtual threads, structured concurrency, and modern concurrent patterns.
Java Build (Maven & Gradle)
Build conventions, dependency management, multi-module projects, and CI patterns.
Java Streams & Collections
Streams API, immutable collections, Collectors, and idiomatic data manipulation.