Quarkus TDD Workflow
TDD guidance for Quarkus 3.x services with 80%+ coverage (unit + integration). Optimized for event-driven architectures with Apache Camel.
When to Use
- New features or REST endpoints
- Bug fixes or refactors
- Adding data access logic, security rules, or reactive streams
- Testing Apache Camel routes and event handlers
- Testing event-driven services with RabbitMQ
- Testing conditional flow logic
- Validating CompletableFuture async operations
- Testing LogContext propagation
Workflow
- Write tests first (they should fail)
- Implement minimal code to pass
- Refactor with tests green
- Enforce coverage with JaCoCo (80%+ target)
Unit Tests with @Nested Organization
Follow this structured approach for comprehensive, readable tests:
Key Testing Patterns
- @Nested Classes: Group tests by method being tested
- @DisplayName: Provide readable test descriptions for test reports
- Naming Convention:
givenX_whenY_thenZfor clarity - AAA Pattern: Explicit
// ARRANGE,// ACT,// ASSERTcomments - @BeforeEach: Setup common test data to reduce duplication
- assertDoesNotThrow: Test success scenarios without catching exceptions
- assertThrows: Test exception scenarios with message validation using AssertJ
- Comprehensive Coverage: Test happy paths, null inputs, edge cases, exceptions
- Verify Interactions: Use Mockito
verify()to ensure methods are called correctly - Never Verify: Use
never()to ensure methods are NOT called in error scenarios
Testing Camel Routes
Testing Event Services
Testing CompletableFuture
Resource Layer Tests (REST Assured)
Integration Tests with Real Database
Coverage with JaCoCo
Maven Configuration (Complete)
Run tests with coverage:
Test Dependencies
Best Practices
Test Organization
- Use
@Nestedclasses to group tests by method being tested - Use
@DisplayNamefor readable test descriptions visible in reports - Follow
givenX_whenY_thenZnaming convention for test methods - Use
@BeforeEachfor common test data setup to reduce duplication
Test Structure
- Follow AAA pattern with explicit comments (
// ARRANGE,// ACT,// ASSERT) - Use
assertDoesNotThrowfor success scenarios - Use
assertThrowsfor exception scenarios with message validation - Verify exception messages match expected values using AssertJ
contains()orisEqualTo()
Test Coverage
- Test happy paths for all public methods
- Test null input handling
- Test edge cases (empty collections, boundary values, negative IDs, blank strings)
- Test exception scenarios comprehensively
- Mock all external dependencies (repositories, services, Camel endpoints)
- Aim for 80%+ line coverage, 70%+ branch coverage
Assertions
- Prefer AssertJ (
assertThat) over JUnit assertions for value checks - Use fluent AssertJ API for readability:
assertThat(list).hasSize(3).contains(item) - For exceptions: use JUnit
assertThrowsto capture, then AssertJ to validate the message - For non-throwing success paths: use JUnit
assertDoesNotThrow - For collections:
extracting(),filteredOn(),containsExactly()
Testing Integration
- Use
@QuarkusTestfor integration tests - Use
@InjectMockto mock dependencies in Quarkus tests - Prefer REST Assured for API testing
- Use
@TestProfilefor test-specific configuration
Event-Driven Testing
- Test Camel routes with
AdviceWithandMockEndpoint - Use
@CamelQuarkusTestannotation (if using standalone Camel tests) - Verify message content, headers, and routing logic
- Test error handling routes separately
- Mock external systems (RabbitMQ, S3, databases) in unit tests
Camel Route Testing
- Use
MockEndpointfor asserting message flow - Use
AdviceWithto modify routes for testing (replace endpoints with mocks) - Test message transformation and marshalling
- Test exception handling and dead letter queues
Testing Async Operations
- Test CompletableFuture success and failure scenarios
- Use
.join()in tests to wait for async completion - Test exception propagation from CompletableFuture
- Verify LogContext propagation to async operations
Performance
- Keep tests fast and isolated
- Run tests in continuous mode:
mvn quarkus:test - Use parameterized tests (
@ParameterizedTest) for input variations - Build reusable test data builders or factory methods
Quarkus-Specific
- Stay on latest LTS version (Quarkus 3.x)
- Test native compilation compatibility periodically
- Use Quarkus test profiles for different scenarios
- Leverage Quarkus dev services for local testing
- Use
@InjectMockinstead of@MockBean(Quarkus-specific)
Verification Best Practices
- Always verify interactions on mocked dependencies
- Use
verify(mock, never())to ensure methods are NOT called in error scenarios - Use
argThat()for complex argument matching - Verify the order of calls when it matters:
InOrderfrom Mockito


