quarkus-tdd skill
Desarrollo guiado por pruebas para Quarkus 3.x LTS usando JUnit 5, Mockito, REST Assured, pruebas Camel y JaCoCo. Usar al agregar funcionalidades, corregir bugs o refactorizar servicios orientados a eventos.
Is the quarkus-tdd skill safe?
Clean: nothing in its files matched our rules. We read 1 file in the folder on 2026-09-28.
No findings.
Install the quarkus-tdd skill
A skill is a folder. Copy it into your agent's skills folder and the agent loads it when the task matches its description.
git clone --depth 1 https://github.com/affaan-m/ECC.git /tmp/ECC mkdir -p ~/.claude/skills cp -r /tmp/ECC/docs/es/skills/quarkus-tdd ~/.claude/skills/quarkus-tdd
In the Claude apps, zip the folder and upload it from the Skills settings. The folder on GitHub
The instructions your agent would load
SKILL.md as published, without the frontmatter. Read it on GitHub
Flujo de Trabajo TDD en Quarkus
Orientación TDD para servicios Quarkus 3.x con 80%+ de cobertura (unit + integración). Optimizado para arquitecturas orientadas a eventos con Apache Camel.
Cuándo Usar
- Nuevas funcionalidades o endpoints REST
- Correcciones de bugs o refactorizaciones
- Agregar lógica de acceso a datos, reglas de seguridad o streams reactivos
- Probar rutas Apache Camel y manejadores de eventos
- Probar servicios orientados a eventos con RabbitMQ
- Probar lógica de flujo condicional
- Validar operaciones asíncronas con CompletableFuture
- Probar propagación de LogContext
Flujo de Trabajo
- Escribir pruebas primero (deben fallar)
- Implementar el código mínimo para que pasen
- Refactorizar con pruebas en verde
- Exigir cobertura con JaCoCo (objetivo 80%+)
Pruebas Unitarias con Organización @Nested
@ExtendWith(MockitoExtension.class)
@DisplayName("Pruebas Unitarias de OrderService")
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("Pruebas para createOrder")
class CreateOrder {
@Test
@DisplayName("Debe persistir orden y publicar evento de fulfillment")
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).createSuccessPatrones Clave de Prueba
- Clases @Nested: Agrupar pruebas por método bajo prueba
- @DisplayName: Proporcionar descripciones legibles para reportes
- Convención de nombres: givenXwhenYthenZ para claridad
- Patrón AAA: Comentarios explícitos // ARRANGE, // ACT, // ASSERT
- @BeforeEach: Configurar datos de prueba comunes para reducir duplicación
- assertDoesNotThrow: Probar escenarios exitosos sin capturar excepciones
- assertThrows: Probar escenarios de excepción con validación de mensajes
- verify(): Asegurar que los métodos sean llamados correctamente
- never(): Asegurar que los métodos NO sean llamados en escenarios de error
Pruebas de Rutas Camel
@QuarkusTest
@DisplayName("Pruebas de Ruta Camel Business Rules")
class BusinessRulesRouteTest {
@Inject
CamelContext camelContext;
@Inject
ProducerTemplate producerTemplate;
@InjectMock
EventService eventService;
@InjectMock
DocumentValidator documentValidator;
private BusinessRulesPayload testPayload;
@BeforeEach
void setUp() {
testPayload = new BusinessRulesPayload();
testPayload.setDocumentId(1L);
testPayload.setFlowProfile(FlowProfile.BASIC);
}
@Nested
@DisplayName("Pruebas para ruta business-rules-publisher")
class BusinessRulesPublisher {
@Test
@DisplayName("Debe publicar mensaje exitosamente en RabbitMQ")
void givenValidPayload_whenPublish_thenMessageSentToQueue() throws Exception {
// ARRANGE
MockEndpoint mockRabbitMQ = camelContext.getEndpoint("mock:rabbitmq", MockEndpoint.class);
mockRabbitMQ.expectedMessageCount(1);
camelContext.getRouteController().stopRoute("business-rules-publisher");
AdviceWith.adviceWith(camelContext, "business-rules-publisher", advice -> {
advice.replaceFromWith("direct:business-rules-publisher");
advice.weaveByToString(".*spring-rabbitmq.*Pruebas de Servicios de Eventos
@ExtendWith(MockitoExtension.class)
@DisplayName("Pruebas Unitarias de EventService")
class EventServiceTest {
@Mock
private EventRepository eventRepository;
@Mock
private ObjectMapper objectMapper;
@InjectMocks
private EventService eventService;
@Nested
@DisplayName("Pruebas para createSuccessEvent")
class CreateSuccessEvent {
@Test
@DisplayName("Debe crear evento de éxito con atributos correctos")
void givenValidPayload_whenCreateSuccessEvent_thenEventPersisted() throws Exception {
// ARRANGE
BusinessRulesPayload testPayload = new BusinessRulesPayload();
testPayload.setDocumentId(1L);
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.getTimestamp() != null
));
}
@Test
@DisplayName("Debe lanzar excepción cuando el payload es null")
void givenNullPaPruebas de CompletableFuture
@ExtendWith(MockitoExtension.class)
class FileStorageServiceTest {
@Mock
private S3Client s3Client;
@Mock
private ExecutorService executorService;
@InjectMocks
private FileStorageService fileStorageService;
@Test
@DisplayName("Debe manejar fallo de S3")
void givenS3Failure_whenUpload_thenCompletableFutureFails() {
// ARRANGE — ejecutar sincrónicamente para que la excepción se propague
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 no disponible"));
// ACT
CompletableFuture<StoredDocumentInfo> future =
fileStorageService.uploadOriginalFile(testInputStream, 1024L,
testLogContext, InvoiceFormat.UBL);
// ASSERT
assertThatThrownBy(() -> future.join())
.isInstanceOf(CompletionException.class)
.hasCauseInstanceOf(StorageException.class)
.hasMessageContaining("S3 no disponible");
}
}Pruebas de Capa de Recurso (REST Assured)
@QuarkusTest
@DisplayName("Pruebas de API DocumentResource")
class DocumentResourceTest {
@InjectMock
DocumentService documentService;
@Test
@DisplayName("Debe crear documento y retornar 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": "Documento de prueba",
"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("Debe retornar 400 para entrada inválida")
void givenInvalidRequest_whenCreate_thenReturns400() {
given()
.contentType(ContentType.JSON)
.body("""
{
"referenceNumber": "",
"description": "Test"
Cobertura con JaCoCo
Configuración Maven (Completa)
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<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>Ejecutar pruebas con cobertura:
mvn clean test
mvn jacoco:report
mvn jacoco:check
# Reporte en: target/site/jacoco/index.htmlDependencias de Prueba
<dependencies>
<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>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>Buenas Prácticas
Organización de Pruebas
- Usar clases @Nested para agrupar pruebas por método bajo prueba
- Usar @DisplayName para descripciones legibles en reportes
- Seguir la convención de nombres givenXwhenYthenZ
- Usar @BeforeEach para configuración de datos comunes
Cobertura de Pruebas
- Probar rutas felices para todos los métodos públicos
- Probar manejo de entradas null
- Probar casos borde (colecciones vacías, valores de frontera)
- Probar escenarios de excepción de forma comprensiva
- Apuntar a 80%+ de cobertura de líneas, 70%+ de ramas
Aserciones
- Preferir AssertJ (assertThat) sobre aserciones JUnit para verificar valores
- Para excepciones: usar JUnit assertThrows para capturar, luego AssertJ para validar
- Para escenarios exitosos sin excepción: usar JUnit assertDoesNotThrow
Pruebas de Integración
- Usar @QuarkusTest para pruebas de integración
- Usar @InjectMock para mockear dependencias en pruebas Quarkus
- Preferir REST Assured para pruebas de API
- Usar @TestProfile para configuración específica de prueba
More skills from affaan-m/ECC
- AaccessibilityWCAG 2.2 レベル AA 標準を用いてインクルーシブなデジタルプロダクトを設計・実装・監査します。Web 用のセマンティック ARIA および Web・ネイティブプラットフォーム(iOS/Android)のアクセシビリティトレイトを生成するために使用します。
- Aagent-architecture-auditエージェントおよび LLM アプリケーション向けのフルスタック診断。12 層のエージェントスタックにおけるラッパーリグレッション、メモリ汚染、ツール規律の失敗、隠れた修復ループ、レンダリング破損を監査します。重要度順の発見事項とコードファーストの修正を生成します。エージェントアプリケーション、自律ループ、または LLM を活用した機能を構築する開発者に必須です。
- Aagent-evalカスタムタスクでコーディングエージェント(Claude Code、Aider、Codex など)をヘッドツーヘッドで比較し、合格率、コスト、時間、一貫性のメトリクスを測定します
- Aagent-harness-constructionAI エージェントのアクション空間、ツール定義、観測フォーマットを設計・最適化して完了率を向上させます。
- Aagent-introspection-debuggingStructured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.
- Aagent-introspection-debuggingキャプチャ、診断、封じ込め回復、内省レポートを使用した AI エージェント障害のための構造化された自己デバッグワークフロー。
- Aagent-payment-x402タスクごとのバジェット、支出コントロール、ノンカストディアルウォレットを備えた x402 決済実行を AI エージェントに追加します。agentwallet-sdk を通じて Base をサポートし、OKX Payments / OKX エージェント決済プロトコルを通じて X Layer をサポートします。
- Aagent-sortBuild an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.
- Aagent-sort並行リポジトリ対応のレビューパスを使用して、スキル、コマンド、ルール、フック、エクストラを DAILY と LIBRARY のバケットに分類することで、特定のリポジトリ向けのエビデンスに基づいた ECC インストール計画を構築します。プロジェクトが完全なバンドルをロードする代わりに実際に必要なものに ECC をトリミングする必要がある場合に使用します。
- Aagentic-engineeringOperate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when AI agents perform most implementation work and humans enforce quality and risk controls.
- Aagentic-engineering評価ファースト実行、分解、コスト対応モデルルーティングを使用してエージェニックエンジニアとして動作します。
- Aagentic-osClaude Code 上に永続的なマルチエージェントオペレーティングシステムを構築します。カーネルアーキテクチャ、スペシャリストエージェント、スラッシュコマンド、ファイルベースのメモリ、スケジュールされた自動化、外部データベースなしの状態管理をカバーします。