用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/aaione/everything-claude-code-zh --skill quarkus-tdd命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Kubernetes 工作负载模式、资源管理、RBAC、probes、autoscaling、ConfigMap/Secret 处理,以及面向生产级部署的 kubectl 调试。
完成任何非平凡任务后使用。智能体按 5 个维度自评输出——准确性、完整性、清晰度、可执行性、简洁性——每项都给出具体证据。生成结构化 1-5 评分卡和具体改进建议。
在 competitive-platform-analysis 产出分层竞品集合后使用。按九个加权维度(定位、声音、视觉工艺、offer packaging、证据、enterprise-readiness、thought leadership、定价、客户 strategic tension)为每个竞品评分,使用明确 1–5 rubrics 和 tension-plot。位于 competitive-report-structure 之前。
基于 SOC 职业分类
正在显示 SKILL.md
| name | quarkus-tdd |
| description | 使用 JUnit 5、Mockito、REST Assured、Camel 测试和 JaCoCo 的 Quarkus 3.x LTS 测试驱动开发。添加功能、修复错误或重构事件驱动服务时使用。 |
| origin | ECC |
TDD guidance for Quarkus 3.x services with 80%+ coverage (unit + integration). Optimized for event-driven architectures with Apache Camel.
Follow this structured approach for comprehensive, readable tests:
@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));
}
}
}
givenX_whenY_thenZ for clarity// ARRANGE, // ACT, // ASSERT commentsverify() to ensure methods are called correctlynever() to ensure methods are NOT called in error scenarios@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();
producerTemplate.sendBody(, testPayload);
mockRabbitMQ.assertIsSatisfied();
assertThat(mockRabbitMQ.getExchanges()).hasSize();
mockRabbitMQ.getExchanges().get().getIn().getBody(String.class);
assertThat(body).contains();
}
Exception {
();
camelContext.addEndpoint(, mockMarshal);
mockMarshal.expectedMessageCount();
camelContext.getRouteController().stopRoute();
AdviceWith.adviceWith(camelContext, , advice -> {
advice.weaveAddLast().to();
});
camelContext.getRouteController().startRoute();
producerTemplate.sendBody(, testPayload);
mockMarshal.assertIsSatisfied();
mockMarshal.getExchanges().get().getIn().getBody(String.class);
assertThat(body).contains();
assertThat(body).contains();
}
}
{
Exception {
camelContext.getEndpoint(, MockEndpoint.class);
mockInvoice.expectedMessageCount();
camelContext.getRouteController().stopRoute();
AdviceWith.adviceWith(camelContext, , advice -> {
advice.weaveByToString().replace().to();
});
camelContext.getRouteController().startRoute();
producerTemplate.sendBodyAndHeader(,
testPayload, , );
mockInvoice.assertIsSatisfied();
}
Exception {
camelContext.getEndpoint(, MockEndpoint.class);
mockError.expectedMessageCount();
camelContext.getRouteController().stopRoute();
AdviceWith.adviceWith(camelContext, , advice -> {
advice.weaveByToString()
.replace().to();
});
camelContext.getRouteController().startRoute();
(documentValidator.validate(any())).thenThrow( ());
producerTemplate.sendBody(, testPayload);
mockError.assertIsSatisfied();
mockError.getExchanges().get().getException();
assertThat(exception).isInstanceOf(ValidationException.class);
assertThat(exception.getMessage()).contains();
}
}
}
@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")
{
;
assertThrows(
NullPointerException.class,
() -> eventService.createSuccessEvent(nullPayload, )
);
assertThat(exception.getMessage()).isEqualTo();
verify(eventRepository, never()).persist(any());
}
}
{
Exception {
;
(objectMapper.writeValueAsString(testPayload)).thenReturn();
assertDoesNotThrow(() ->
eventService.createErrorEvent(testPayload, , errorMessage));
verify(eventRepository).persist(argThat(event ->
event.getType().equals() &&
event.getStatus() == EventStatus.ERROR &&
event.getErrorMessage().equals(errorMessage) &&
event.getPayload().equals()
));
}
{
assertThrows(
IllegalArgumentException.class,
() -> eventService.createErrorEvent(testPayload, , blankMessage)
);
assertThat(exception.getMessage()).contains();
}
}
}
@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, ,
testLogContext, InvoiceFormat.UBL);
future.join();
assertThat(result).isNotNull();
assertThat(result.getPath()).isNotBlank();
assertThat(result.getSize()).isEqualTo();
assertThat(result.getUploadedAt()).isNotNull();
verify(s3Client).putObject(any(PutObjectRequest.class), any(RequestBody.class));
}
{
doAnswer(invocation -> {
((Runnable) invocation.getArgument()).run();
;
}).(executorService).execute(any(Runnable.class));
(s3Client.putObject(any(PutObjectRequest.class), any(RequestBody.class)))
.thenThrow( ());
CompletableFuture<StoredDocumentInfo> future =
fileStorageService.uploadOriginalFile(testInputStream, ,
testLogContext, InvoiceFormat.UBL);
assertThatThrownBy(() -> future.join())
.isInstanceOf(CompletionException.class)
.hasCauseInstanceOf(StorageException.class)
.hasMessageContaining();
}
Exception {
AtomicReference<LogContext> capturedContext = <>();
doAnswer(invocation -> {
capturedContext.set(CustomLog.getCurrentContext());
((Runnable) invocation.getArgument()).run();
;
}).(executorService).execute(any(Runnable.class));
fileStorageService.uploadOriginalFile(testInputStream, ,
testLogContext, InvoiceFormat.UBL).join();
assertThat(capturedContext.get()).isNotNull();
assertThat(capturedContext.get().get()).isEqualTo();
}
}
}
@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);
given()
.contentType(ContentType.JSON)
.body()
.().post()
.then()
.statusCode()
.header(, containsString())
.body(, equalTo());
}
{
given()
.contentType(ContentType.JSON)
.body()
.().post()
.then()
.statusCode();
}
}
Document {
();
document.setId(id);
document.setReferenceNumber(referenceNumber);
document.setStatus(DocumentStatus.PENDING);
document;
}
}
@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"));
}
}
<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</>
check
BUNDLE
LINE
COVEREDRATIO
0.80
BRANCH
COVEREDRATIO
0.70
Run tests with coverage:
mvn clean test
mvn jacoco:report
mvn jacoco:check
# Report at: target/site/jacoco/index.html
<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</>
assertj-core
3.24.2
test
io.rest-assured
rest-assured
test
org.apache.camel.quarkus
camel-quarkus-junit5
test
@Nested classes to group tests by method being tested@DisplayName for readable test descriptions visible in reportsgivenX_whenY_thenZ naming convention for test methods@BeforeEach for common test data setup to reduce duplication// ARRANGE, // ACT, // ASSERT)assertDoesNotThrow for success scenariosassertThrows for exception scenarios with message validationcontains() or isEqualTo()assertThat) over JUnit assertions for value checksassertThat(list).hasSize(3).contains(item)assertThrows to capture, then AssertJ to validate the messageassertDoesNotThrowextracting(), filteredOn(), containsExactly()@QuarkusTest for integration tests@InjectMock to mock dependencies in Quarkus tests@TestProfile for test-specific configurationAdviceWith and MockEndpoint@CamelQuarkusTest annotation (if using standalone Camel tests)MockEndpoint for asserting message flowAdviceWith to modify routes for testing (replace endpoints with mocks).join() in tests to wait for async completionmvn quarkus:test@ParameterizedTest) for input variations@InjectMock instead of @MockBean (Quarkus-specific)verify(mock, never()) to ensure methods are NOT called in error scenariosargThat() for complex argument matchingInOrder from Mockito