Quarkus Tdd

affaan-m/ECC/skills/quarkus-tdd

by affaan-mef648e01899ba3e8dc6371642deaaf64b4477775No license275K starsListed Oct 9, 2026Updated Oct 9, 2026Repository updated 4 days ago

Test-driven development for Quarkus 3.x LTS using JUnit 5, Mockito, REST Assured, Camel testing, and JaCoCo. Use when adding features, fixing bugs, or refactoring event-driven services.

Instructions onlySoftware Development
AI-generated overview

Guides test-driven development for Quarkus 3.x services using JUnit 5, Mockito, REST Assured, Camel testing and JaCoCo.

What it does
This skill provides a TDD workflow for Quarkus 3.x services: write failing tests first, implement minimal code, refactor with tests green, and enforce 80%+ coverage with JaCoCo. It supplies worked examples for unit tests with @Nested organization and Mockito mocks, Camel route tests using AdviceWith and MockEndpoint, event service tests, CompletableFuture and LogContext propagation tests, REST Assured resource tests, and integration tests against a real database. It also lists the Maven test dependencies and JaCoCo plugin configuration needed for the setup.
When to use it
Use it when adding features or REST endpoints, fixing bugs, or refactoring Quarkus services, especially event-driven ones with Apache Camel, RabbitMQ, reactive streams, or async CompletableFuture operations. It also fits when adding data access logic, security rules, or conditional flow logic that needs test coverage.
Requirements
Requires a Quarkus 3.x LTS Java project with Maven and test dependencies: quarkus-junit5, quarkus-junit5-mockito, mockito-core, assertj-core, rest-assured, camel-quarkus-junit5, plus JaCoCo for coverage. Ships no scripts; it is instructions and code examples only.

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

  1. Write tests first (they should fail)
  2. Implement minimal code to pass
  3. Refactor with tests green
  4. Enforce coverage with JaCoCo (80%+ target)

Unit Tests with @Nested Organization

Follow this structured approach for comprehensive, readable tests:

java
@ExtendWith(MockitoExtension.class)@DisplayName("OrderService Unit Tests")class OrderServiceTest {
  @Mock  private OrderRepository orderRepository;
  @Mock  private EventService eventService;
  @Mock  private FulfillmentPublisher fulfillmentPublisher;
  @InjectMocks  private OrderService orderService;
  private CreateOrderCommand validCommand;
  @BeforeEach  void setUp() {    validCommand = new CreateOrderCommand(        "customer-123",        List.of(new OrderLine("sku-123", 2))    );  }
  @Nested  @DisplayName("Tests for createOrder")  class CreateOrder {
    @Test    @DisplayName("Should persist order and publish fulfillment event")    void givenValidCommand_whenCreateOrder_thenPersistsAndPublishes() {      // ARRANGE      doNothing().when(orderRepository).persist(any(Order.class));
      // ACT      OrderReceipt receipt = orderService.createOrder(validCommand);
      // ASSERT      assertThat(receipt).isNotNull();      assertThat(receipt.customerId()).isEqualTo("customer-123");      verify(orderRepository).persist(any(Order.class));      verify(fulfillmentPublisher).publishAsync(receipt);      verify(eventService).createSuccessEvent(receipt, "ORDER_CREATED");    }
    @Test    @DisplayName("Should reject missing customer id")    void givenMissingCustomerId_whenCreateOrder_thenThrowsBadRequest() {      // ARRANGE      CreateOrderCommand invalid = new CreateOrderCommand("", validCommand.lines());
      // ACT & ASSERT      WebApplicationException exception = assertThrows(          WebApplicationException.class,          () -> orderService.createOrder(invalid)      );
      assertThat(exception.getResponse().getStatus()).isEqualTo(400);      verify(orderRepository, never()).persist(any(Order.class));      verify(fulfillmentPublisher, never()).publishAsync(any());    }
    @Test    @DisplayName("Should record error event when persistence fails")    void givenPersistenceFailure_whenCreateOrder_thenRecordsErrorEvent() {      // ARRANGE      doThrow(new PersistenceException("database unavailable"))          .when(orderRepository).persist(any(Order.class));
      // ACT & ASSERT      PersistenceException exception = assertThrows(          PersistenceException.class,          () -> orderService.createOrder(validCommand)      );
      assertThat(exception.getMessage()).contains("database unavailable");      verify(eventService).createErrorEvent(          eq(validCommand),          eq("ORDER_CREATE_FAILED"),          contains("database unavailable")      );      verify(fulfillmentPublisher, never()).publishAsync(any());    }
    @Test    @DisplayName("Should reject null commands")    void givenNullCommand_whenCreateOrder_thenThrowsNullPointerException() {      // ACT & ASSERT      assertThrows(          NullPointerException.class,          () -> orderService.createOrder(null)      );
      verify(orderRepository, never()).persist(any(Order.class));    }  }}

Key Testing Patterns

  1. @Nested Classes: Group tests by method being tested
  2. @DisplayName: Provide readable test descriptions for test reports
  3. Naming Convention: givenX_whenY_thenZ for clarity
  4. AAA Pattern: Explicit // ARRANGE, // ACT, // ASSERT comments
  5. @BeforeEach: Setup common test data to reduce duplication
  6. assertDoesNotThrow: Test success scenarios without catching exceptions
  7. assertThrows: Test exception scenarios with message validation using AssertJ
  8. Comprehensive Coverage: Test happy paths, null inputs, edge cases, exceptions
  9. Verify Interactions: Use Mockito verify() to ensure methods are called correctly
  10. Never Verify: Use never() to ensure methods are NOT called in error scenarios

Testing Camel Routes

java
@QuarkusTest@DisplayName("Business Rules Camel Route Tests")class BusinessRulesRouteTest {
  @Inject  CamelContext camelContext;
  @Inject  ProducerTemplate producerTemplate;
  @InjectMock  EventService eventService;
  @InjectMock  DocumentValidator documentValidator;
  private BusinessRulesPayload testPayload;
  @BeforeEach  void setUp() {    // ARRANGE - Test data    testPayload = new BusinessRulesPayload();    testPayload.setDocumentId(1L);    testPayload.setFlowProfile(FlowProfile.BASIC);  }
  @Nested  @DisplayName("Tests for business-rules-publisher route")  class BusinessRulesPublisher {
    @Test    @DisplayName("Should successfully publish message to RabbitMQ")    void givenValidPayload_whenPublish_thenMessageSentToQueue() throws Exception {      // ARRANGE      MockEndpoint mockRabbitMQ = camelContext.getEndpoint("mock:rabbitmq", MockEndpoint.class);      mockRabbitMQ.expectedMessageCount(1);
      // Replace real endpoint with mock for testing      camelContext.getRouteController().stopRoute("business-rules-publisher");      AdviceWith.adviceWith(camelContext, "business-rules-publisher", advice -> {        advice.replaceFromWith("direct:business-rules-publisher");        advice.weaveByToString(".*spring-rabbitmq.*").replace().to("mock:rabbitmq");      });      camelContext.getRouteController().startRoute("business-rules-publisher");
      // ACT      producerTemplate.sendBody("direct:business-rules-publisher", testPayload);
      // ASSERT — body is a JSON String after .marshal().json(JsonLibrary.Jackson)      mockRabbitMQ.assertIsSatisfied(5000);
      assertThat(mockRabbitMQ.getExchanges()).hasSize(1);      String body = mockRabbitMQ.getExchanges().get(0).getIn().getBody(String.class);      assertThat(body).contains("\"documentId\":1");    }
    @Test    @DisplayName("Should handle marshalling to JSON")    void givenPayload_whenPublish_thenMarshalledToJson() throws Exception {      // ARRANGE      MockEndpoint mockMarshal = new MockEndpoint("mock:marshal");      camelContext.addEndpoint("mock:marshal", mockMarshal);      mockMarshal.expectedMessageCount(1);
      camelContext.getRouteController().stopRoute("business-rules-publisher");      AdviceWith.adviceWith(camelContext, "business-rules-publisher", advice -> {        advice.weaveAddLast().to("mock:marshal");      });      camelContext.getRouteController().startRoute("business-rules-publisher");
      // ACT      producerTemplate.sendBody("direct:business-rules-publisher", testPayload);
      // ASSERT      mockMarshal.assertIsSatisfied(5000);
      String body = mockMarshal.getExchanges().get(0).getIn().getBody(String.class);      assertThat(body).contains("\"documentId\":1");      assertThat(body).contains("\"flowProfile\":\"BASIC\"");    }  }
  @Nested  @DisplayName("Tests for document-processing route")  class DocumentProcessing {
    @Test    @DisplayName("Should route invoice to correct processor")    void givenInvoiceType_whenProcess_thenRoutesToInvoiceProcessor() throws Exception {      // ARRANGE      MockEndpoint mockInvoice = camelContext.getEndpoint("mock:invoice", MockEndpoint.class);      mockInvoice.expectedMessageCount(1);
      camelContext.getRouteController().stopRoute("document-processing");      AdviceWith.adviceWith(camelContext, "document-processing", advice -> {        advice.weaveByToString(".*direct:process-invoice.*").replace().to("mock:invoice");      });      camelContext.getRouteController().startRoute("document-processing");
      // ACT      producerTemplate.sendBodyAndHeader("direct:process-document",          testPayload, "documentType", "INVOICE");
      // ASSERT      mockInvoice.assertIsSatisfied(5000);    }
    @Test    @DisplayName("Should handle validation errors gracefully")    void givenValidationError_whenProcess_thenRoutesToErrorHandler() throws Exception {      // ARRANGE      MockEndpoint mockError = camelContext.getEndpoint("mock:error", MockEndpoint.class);      mockError.expectedMessageCount(1);
      camelContext.getRouteController().stopRoute("document-processing");      AdviceWith.adviceWith(camelContext, "document-processing", advice -> {        advice.weaveByToString(".*direct:validation-error-handler.*")            .replace().to("mock:error");      });      camelContext.getRouteController().startRoute("document-processing");
      // Mock validator bean to throw exception      when(documentValidator.validate(any())).thenThrow(new ValidationException("Invalid document"));
      // ACT      producerTemplate.sendBody("direct:process-document", testPayload);
      // ASSERT      mockError.assertIsSatisfied(5000);
      Exception exception = mockError.getExchanges().get(0).getException();      assertThat(exception).isInstanceOf(ValidationException.class);      assertThat(exception.getMessage()).contains("Invalid document");    }  }}

Testing Event Services

java
@ExtendWith(MockitoExtension.class)@DisplayName("EventService Unit Tests")class EventServiceTest {
  @Mock  private EventRepository eventRepository;
  @Mock  private ObjectMapper objectMapper;
  @InjectMocks  private EventService eventService;
  private BusinessRulesPayload testPayload;
  @BeforeEach  void setUp() {    // ARRANGE    testPayload = new BusinessRulesPayload();    testPayload.setDocumentId(1L);  }
  @Nested  @DisplayName("Tests for createSuccessEvent")  class CreateSuccessEvent {
    @Test    @DisplayName("Should create success event with correct attributes")    void givenValidPayload_whenCreateSuccessEvent_thenEventPersisted() throws Exception {      // ARRANGE      when(objectMapper.writeValueAsString(testPayload)).thenReturn("{\"documentId\":1}");
      // ACT      assertDoesNotThrow(() ->          eventService.createSuccessEvent(testPayload, "DOCUMENT_PROCESSED"));
      // ASSERT      verify(eventRepository).persist(argThat(event ->          event.getType().equals("DOCUMENT_PROCESSED") &&          event.getStatus() == EventStatus.SUCCESS &&          event.getPayload().equals("{\"documentId\":1}") &&          event.getTimestamp() != null      ));    }
    @Test    @DisplayName("Should throw exception when payload is null")    void givenNullPayload_whenCreateSuccessEvent_thenThrowsException() {      // ARRANGE      Object nullPayload = null;
      // ACT & ASSERT      NullPointerException exception = assertThrows(          NullPointerException.class,          () -> eventService.createSuccessEvent(nullPayload, "EVENT_TYPE")      );
      assertThat(exception.getMessage()).isEqualTo("Payload cannot be null");      verify(eventRepository, never()).persist(any());    }  }
  @Nested  @DisplayName("Tests for createErrorEvent")  class CreateErrorEvent {
    @Test    @DisplayName("Should create error event with error message")    void givenError_whenCreateErrorEvent_thenEventPersistedWithMessage() throws Exception {      // ARRANGE      String errorMessage = "Processing failed";      when(objectMapper.writeValueAsString(testPayload)).thenReturn("{\"documentId\":1}");
      // ACT      assertDoesNotThrow(() ->          eventService.createErrorEvent(testPayload, "PROCESSING_ERROR", errorMessage));
      // ASSERT      verify(eventRepository).persist(argThat(event ->          event.getType().equals("PROCESSING_ERROR") &&          event.getStatus() == EventStatus.ERROR &&          event.getErrorMessage().equals(errorMessage) &&          event.getPayload().equals("{\"documentId\":1}")      ));    }
    @ParameterizedTest    @DisplayName("Should reject invalid error messages")    @ValueSource(strings = {"", " "})    void givenBlankErrorMessage_whenCreateErrorEvent_thenThrowsException(String blankMessage) {      // ACT & ASSERT      IllegalArgumentException exception = assertThrows(          IllegalArgumentException.class,          () -> eventService.createErrorEvent(testPayload, "ERROR", blankMessage)      );
      assertThat(exception.getMessage()).contains("Error message cannot be blank");    }  }}

Testing CompletableFuture

java
@ExtendWith(MockitoExtension.class)@DisplayName("FileStorageService Unit Tests")class FileStorageServiceTest {
  @Mock  private S3Client s3Client;
  @Mock  private ExecutorService executorService;
  @InjectMocks  private FileStorageService fileStorageService;
  private InputStream testInputStream;  private LogContext testLogContext;
  @BeforeEach  void setUp() {    // ARRANGE    testInputStream = new ByteArrayInputStream("test content".getBytes());    testLogContext = new LogContext();    testLogContext.put("traceId", "trace-123");  }
  @Nested  @DisplayName("Tests for uploadOriginalFile")  class UploadOriginalFile {
    @Test    @DisplayName("Should successfully upload file and return document info")    void givenValidFile_whenUpload_thenReturnsDocumentInfo() throws Exception {      // ARRANGE      doAnswer(invocation -> {        ((Runnable) invocation.getArgument(0)).run();        return null;      }).when(executorService).execute(any(Runnable.class));
      when(s3Client.putObject(any(PutObjectRequest.class), any(RequestBody.class)))          .thenReturn(PutObjectResponse.builder().build());
      // ACT      CompletableFuture<StoredDocumentInfo> future =          fileStorageService.uploadOriginalFile(testInputStream, 1024L,              testLogContext, InvoiceFormat.UBL);
      StoredDocumentInfo result = future.join();
      // ASSERT      assertThat(result).isNotNull();      assertThat(result.getPath()).isNotBlank();      assertThat(result.getSize()).isEqualTo(1024L);      assertThat(result.getUploadedAt()).isNotNull();
      verify(s3Client).putObject(any(PutObjectRequest.class), any(RequestBody.class));    }
    @Test    @DisplayName("Should handle S3 upload failure")    void givenS3Failure_whenUpload_thenCompletableFutureFails() {      // ARRANGE — run synchronously so exception propagates through the future      doAnswer(invocation -> {        ((Runnable) invocation.getArgument(0)).run();        return null;      }).when(executorService).execute(any(Runnable.class));
      when(s3Client.putObject(any(PutObjectRequest.class), any(RequestBody.class)))          .thenThrow(new StorageException("S3 unavailable"));
      // ACT      CompletableFuture<StoredDocumentInfo> future =          fileStorageService.uploadOriginalFile(testInputStream, 1024L,              testLogContext, InvoiceFormat.UBL);
      // ASSERT      assertThatThrownBy(() -> future.join())          .isInstanceOf(CompletionException.class)          .hasCauseInstanceOf(StorageException.class)          .hasMessageContaining("S3 unavailable");    }
    @Test    @DisplayName("Should propagate LogContext to async operation")    void givenLogContext_whenUpload_thenContextPropagated() throws Exception {      // ARRANGE      AtomicReference<LogContext> capturedContext = new AtomicReference<>();
      doAnswer(invocation -> {        capturedContext.set(CustomLog.getCurrentContext());        ((Runnable) invocation.getArgument(0)).run();        return null;      }).when(executorService).execute(any(Runnable.class));
      // ACT      fileStorageService.uploadOriginalFile(testInputStream, 1024L,          testLogContext, InvoiceFormat.UBL).join();
      // ASSERT      assertThat(capturedContext.get()).isNotNull();      assertThat(capturedContext.get().get("traceId")).isEqualTo("trace-123");    }  }}

Resource Layer Tests (REST Assured)

java
@QuarkusTest@DisplayName("DocumentResource API Tests")class DocumentResourceTest {
  @InjectMock  DocumentService documentService;
  @Nested  @DisplayName("Tests for GET /api/documents")  class ListDocuments {
    @Test    @DisplayName("Should return list of documents")    void givenDocumentsExist_whenList_thenReturnsOk() {      // ARRANGE      List<Document> documents = List.of(createDocument(1L, "DOC-001"));      when(documentService.list(0, 20)).thenReturn(documents);
      // ACT & ASSERT      given()          .when().get("/api/documents")          .then()          .statusCode(200)          .body("$.size()", is(1))          .body("[0].referenceNumber", equalTo("DOC-001"));    }  }
  @Nested  @DisplayName("Tests for POST /api/documents")  class CreateDocument {
    @Test    @DisplayName("Should create document and return 201")    void givenValidRequest_whenCreate_thenReturns201() {      // ARRANGE      Document document = createDocument(1L, "DOC-001");      when(documentService.create(any())).thenReturn(document);
      // ACT & ASSERT      given()          .contentType(ContentType.JSON)          .body("""              {                "referenceNumber": "DOC-001",                "description": "Test document",                "validUntil": "2030-01-01T00:00:00Z",                "categories": ["test"]              }              """)          .when().post("/api/documents")          .then()          .statusCode(201)          .header("Location", containsString("/api/documents/1"))          .body("referenceNumber", equalTo("DOC-001"));    }
    @Test    @DisplayName("Should return 400 for invalid input")    void givenInvalidRequest_whenCreate_thenReturns400() {      // ACT & ASSERT      given()          .contentType(ContentType.JSON)          .body("""              {                "referenceNumber": "",                "description": "Test"              }              """)          .when().post("/api/documents")          .then()          .statusCode(400);    }  }
  private Document createDocument(Long id, String referenceNumber) {    Document document = new Document();    document.setId(id);    document.setReferenceNumber(referenceNumber);    document.setStatus(DocumentStatus.PENDING);    return document;  }}

Integration Tests with Real Database

java
@QuarkusTest@TestProfile(IntegrationTestProfile.class)@DisplayName("Document Integration Tests")class DocumentIntegrationTest {
  @Test  @Transactional  @DisplayName("Should create and retrieve document via API")  void givenNewDocument_whenCreateAndRetrieve_thenSuccessful() {    // ACT - Create via API    Long id = given()        .contentType(ContentType.JSON)        .body("""            {              "referenceNumber": "INT-001",              "description": "Integration test",              "validUntil": "2030-01-01T00:00:00Z",              "categories": ["test"]            }            """)        .when().post("/api/documents")        .then()        .statusCode(201)        .extract().path("id");
    // ASSERT - Retrieve via API    given()        .when().get("/api/documents/" + id)        .then()        .statusCode(200)        .body("referenceNumber", equalTo("INT-001"));  }}

Coverage with JaCoCo

Maven Configuration (Complete)

xml
<plugin>  <groupId>org.jacoco</groupId>  <artifactId>jacoco-maven-plugin</artifactId>  <version>0.8.13</version>  <executions>    <!-- Prepare agent for test execution -->    <execution>      <id>prepare-agent</id>      <goals>        <goal>prepare-agent</goal>      </goals>    </execution>
    <!-- Generate coverage report -->    <execution>      <id>report</id>      <phase>verify</phase>      <goals>        <goal>report</goal>      </goals>    </execution>
    <!-- Enforce coverage thresholds -->    <execution>      <id>check</id>      <goals>        <goal>check</goal>      </goals>      <configuration>        <rules>          <rule>            <element>BUNDLE</element>            <limits>              <limit>                <counter>LINE</counter>                <value>COVEREDRATIO</value>                <minimum>0.80</minimum>              </limit>              <limit>                <counter>BRANCH</counter>                <value>COVEREDRATIO</value>                <minimum>0.70</minimum>              </limit>            </limits>          </rule>        </rules>      </configuration>    </execution>  </executions></plugin>

Run tests with coverage:

bash
mvn clean testmvn jacoco:reportmvn jacoco:check
# Report at: target/site/jacoco/index.html

Test Dependencies

xml
<dependencies>    <!-- Quarkus Testing -->    <dependency>        <groupId>io.quarkus</groupId>        <artifactId>quarkus-junit5</artifactId>        <scope>test</scope>    </dependency>    <dependency>        <groupId>io.quarkus</groupId>        <artifactId>quarkus-junit5-mockito</artifactId>        <scope>test</scope>    </dependency>
    <!-- Mockito -->    <dependency>        <groupId>org.mockito</groupId>        <artifactId>mockito-core</artifactId>        <scope>test</scope>    </dependency>
    <!-- AssertJ (preferred over JUnit assertions) -->    <dependency>        <groupId>org.assertj</groupId>        <artifactId>assertj-core</artifactId>        <version>3.24.2</version>        <scope>test</scope>    </dependency>
    <!-- REST Assured -->    <dependency>        <groupId>io.rest-assured</groupId>        <artifactId>rest-assured</artifactId>        <scope>test</scope>    </dependency>
    <!-- Camel Testing -->    <dependency>        <groupId>org.apache.camel.quarkus</groupId>        <artifactId>camel-quarkus-junit5</artifactId>        <scope>test</scope>    </dependency></dependencies>

Best Practices

Test Organization

  • Use @Nested classes to group tests by method being tested
  • Use @DisplayName for readable test descriptions visible in reports
  • Follow givenX_whenY_thenZ naming convention for test methods
  • Use @BeforeEach for common test data setup to reduce duplication

Test Structure

  • Follow AAA pattern with explicit comments (// ARRANGE, // ACT, // ASSERT)
  • Use assertDoesNotThrow for success scenarios
  • Use assertThrows for exception scenarios with message validation
  • Verify exception messages match expected values using AssertJ contains() or isEqualTo()

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 assertThrows to capture, then AssertJ to validate the message
  • For non-throwing success paths: use JUnit assertDoesNotThrow
  • For collections: extracting(), filteredOn(), containsExactly()

Testing Integration

  • Use @QuarkusTest for integration tests
  • Use @InjectMock to mock dependencies in Quarkus tests
  • Prefer REST Assured for API testing
  • Use @TestProfile for test-specific configuration

Event-Driven Testing

  • Test Camel routes with AdviceWith and MockEndpoint
  • Use @CamelQuarkusTest annotation (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 MockEndpoint for asserting message flow
  • Use AdviceWith to 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 @InjectMock instead 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: InOrder from Mockito

Source and attribution

Source:affaan-m/ECCinskills/quarkus-tddat commitef648e0

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal