@saulwade/swl-ses 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: java-patrones
|
|
3
|
+
description: >
|
|
4
|
+
Patrones de diseño idiomáticos en Java moderno: records, sealed interfaces,
|
|
5
|
+
Optional correcto, switch expressions, method references y Comparator.
|
|
6
|
+
Cargar cuando se diseñe arquitectura Java 17+ o se refactorice código legacy.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
herramientasPermitidas: [Read, Glob, Grep]
|
|
9
|
+
exclusiones:
|
|
10
|
+
- "No cargar para implementar controllers, services o entidades Spring Boot — para implementación concreta cargar `java-experto`."
|
|
11
|
+
- "No cargar para escribir tests JUnit o de integración — para testing cargar `java-testing`."
|
|
12
|
+
- "No cargar para errores de compilación Java — para build errors cargar `build-errors-java`."
|
|
13
|
+
- "No cargar para patrones de diseño genéricos (GoF) sin contexto Java — este skill cubre idiomas específicos de Java 17+ como sealed classes y pattern matching."
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
---
|
|
16
|
+
# Java Patrones — Diseño Idiomático Java Moderno
|
|
17
|
+
|
|
18
|
+
Cubre los patrones que produce código Java moderno legible y mantenible:
|
|
19
|
+
value objects con records, dominios cerrados con sealed, Optional correcto,
|
|
20
|
+
switch expressions, JPMS básico y composición funcional.
|
|
21
|
+
|
|
22
|
+
## Cuándo cargar este skill
|
|
23
|
+
|
|
24
|
+
Invoca `Skill("java-patrones")` cuando:
|
|
25
|
+
|
|
26
|
+
- Se diseñen value objects, command objects o result types en Java
|
|
27
|
+
- Se refactorice código con instanceof encadenados o switch con strings
|
|
28
|
+
- Se diseñe la arquitectura de un módulo nuevo en Java 17+
|
|
29
|
+
- Se revise código legacy que use patrones obsoletos
|
|
30
|
+
- Se implementen Comparators, collectors o pipelines funcionales
|
|
31
|
+
|
|
32
|
+
## Cuándo NO cargar
|
|
33
|
+
|
|
34
|
+
- La pregunta es sobre implementar controllers, services o entidades JPA — para implementación concreta cargar `java-experto`.
|
|
35
|
+
- La tarea es escribir tests JUnit, MockMvc o de integración — cargar `java-testing`.
|
|
36
|
+
- Los errores son de compilación Java — cargar `build-errors-java`.
|
|
37
|
+
- La discusión es sobre patrones GoF genéricos (Singleton, Observer) sin contexto Java moderno — este skill cubre idiomas específicos de Java 17+ como records, sealed e instanceof patterns.
|
|
38
|
+
|
|
39
|
+
## Conceptos clave
|
|
40
|
+
|
|
41
|
+
### Value Objects con Records
|
|
42
|
+
|
|
43
|
+
Un record es un transportador de datos inmutable con igualdad por valor.
|
|
44
|
+
Ideal para DTOs, value objects de dominio y parámetros de comando.
|
|
45
|
+
Genera automáticamente: constructor canónico, accessors, equals, hashCode, toString.
|
|
46
|
+
|
|
47
|
+
### Dominios cerrados con Sealed Interfaces
|
|
48
|
+
|
|
49
|
+
`sealed interface` + `permits` garantiza en tiempo de compilación que el
|
|
50
|
+
conjunto de implementaciones es conocido y finito. El compilador puede verificar
|
|
51
|
+
exhaustividad en switch expressions.
|
|
52
|
+
|
|
53
|
+
### Pattern Matching
|
|
54
|
+
|
|
55
|
+
`instanceof` con binding variable y switch con patterns eliminan casts manuales
|
|
56
|
+
y reducen la verbosidad de la navegación de tipos.
|
|
57
|
+
|
|
58
|
+
## Reglas obligatorias
|
|
59
|
+
|
|
60
|
+
### Records para value objects — no POJOs mutables
|
|
61
|
+
|
|
62
|
+
Value objects que representan conceptos del dominio (Money, Email, OrderId)
|
|
63
|
+
deben ser records inmutables. Los POJOs mutables con setters son frágiles en
|
|
64
|
+
contextos concurrentes y dificultan el razonamiento sobre el estado.
|
|
65
|
+
|
|
66
|
+
### Optional solo como tipo de retorno — nunca como parámetro
|
|
67
|
+
|
|
68
|
+
`Optional` como parámetro de método fuerza al llamador a envolver valores en
|
|
69
|
+
Optional innecesariamente y no aporta claridad. Como tipo de retorno comunica
|
|
70
|
+
explícitamente que el valor puede no estar presente.
|
|
71
|
+
|
|
72
|
+
```java
|
|
73
|
+
// MAL — Optional como parametro
|
|
74
|
+
void buscar(Optional<String> filtro) { ... }
|
|
75
|
+
|
|
76
|
+
// BIEN — Optional como retorno
|
|
77
|
+
Optional<Usuario> buscarPorEmail(String email) { ... }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Switch expression sobre switch statement para asignacion
|
|
81
|
+
|
|
82
|
+
El switch expression es exhaustivo (el compilador obliga a cubrir todos los
|
|
83
|
+
casos) y retorna un valor directamente, eliminando variables mutables temporales.
|
|
84
|
+
|
|
85
|
+
### Comparator.comparing para ordenamiento — no implementar Comparable en DTOs
|
|
86
|
+
|
|
87
|
+
Los DTOs y records no deben implementar `Comparable` porque el criterio de
|
|
88
|
+
ordenamiento depende del contexto de uso, no del tipo. Usar `Comparator.comparing`
|
|
89
|
+
en el sitio de uso.
|
|
90
|
+
|
|
91
|
+
## Patrones recomendados
|
|
92
|
+
|
|
93
|
+
### Record con validación en constructor canónico
|
|
94
|
+
|
|
95
|
+
```java
|
|
96
|
+
public record Email(String valor) {
|
|
97
|
+
public Email {
|
|
98
|
+
Objects.requireNonNull(valor, "email no puede ser null");
|
|
99
|
+
if (!valor.contains("@")) {
|
|
100
|
+
throw new IllegalArgumentException("Email invalido: " + valor);
|
|
101
|
+
}
|
|
102
|
+
valor = valor.toLowerCase().trim(); // normalizacion en constructor canonico
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Sealed interface como result type
|
|
108
|
+
|
|
109
|
+
```java
|
|
110
|
+
public sealed interface ResultadoValidacion
|
|
111
|
+
permits ResultadoValidacion.Valido, ResultadoValidacion.Invalido {
|
|
112
|
+
|
|
113
|
+
record Valido() implements ResultadoValidacion {}
|
|
114
|
+
record Invalido(List<String> errores) implements ResultadoValidacion {
|
|
115
|
+
public Invalido {
|
|
116
|
+
errores = List.copyOf(errores); // copia defensiva
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static ResultadoValidacion valido() { return new Valido(); }
|
|
121
|
+
static ResultadoValidacion invalido(String... errores) {
|
|
122
|
+
return new Invalido(List.of(errores));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Uso
|
|
127
|
+
ResultadoValidacion resultado = validar(pedido);
|
|
128
|
+
String mensaje = switch (resultado) {
|
|
129
|
+
case ResultadoValidacion.Valido v -> "OK";
|
|
130
|
+
case ResultadoValidacion.Invalido i ->
|
|
131
|
+
"Errores: " + String.join(", ", i.errores());
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Pattern matching con instanceof
|
|
136
|
+
|
|
137
|
+
```java
|
|
138
|
+
// Antes de Java 16 (verboso)
|
|
139
|
+
if (objeto instanceof String) {
|
|
140
|
+
String s = (String) objeto;
|
|
141
|
+
return s.toUpperCase();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Java 16+ con binding variable
|
|
145
|
+
if (objeto instanceof String s) {
|
|
146
|
+
return s.toUpperCase();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Java 21+ con switch pattern matching
|
|
150
|
+
return switch (objeto) {
|
|
151
|
+
case String s when s.isBlank() -> "VACIO";
|
|
152
|
+
case String s -> s.toUpperCase();
|
|
153
|
+
case Integer i -> String.valueOf(i);
|
|
154
|
+
case null -> "NULL";
|
|
155
|
+
default -> objeto.toString();
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Comparator composition
|
|
160
|
+
|
|
161
|
+
```java
|
|
162
|
+
// Ordenar por apellido, luego nombre, luego edad descendente
|
|
163
|
+
Comparator<Usuario> ordenamiento = Comparator
|
|
164
|
+
.comparing(Usuario::apellido)
|
|
165
|
+
.thenComparing(Usuario::nombre)
|
|
166
|
+
.thenComparing(Comparator.comparingInt(Usuario::edad).reversed());
|
|
167
|
+
|
|
168
|
+
usuarios.sort(ordenamiento);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Optional correcto
|
|
172
|
+
|
|
173
|
+
```java
|
|
174
|
+
// Cadena de Optional sin null checks
|
|
175
|
+
return repo.findByEmail(email) // Optional<Usuario>
|
|
176
|
+
.filter(u -> u.estatus() == Estatus.ACTIVO) // solo activos
|
|
177
|
+
.map(u -> new UsuarioResponse(u.id(), u.nombre())) // mapear a DTO
|
|
178
|
+
.orElseThrow(() -> new NotFoundException("Usuario no encontrado o inactivo"));
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Method references en lugar de lambdas redundantes
|
|
182
|
+
|
|
183
|
+
```java
|
|
184
|
+
// MAL — lambda que solo delega
|
|
185
|
+
usuarios.stream().map(u -> u.getNombre()).collect(toList());
|
|
186
|
+
lista.forEach(item -> System.out.println(item));
|
|
187
|
+
|
|
188
|
+
// BIEN — method reference directo
|
|
189
|
+
usuarios.stream().map(Usuario::getNombre).collect(toList());
|
|
190
|
+
lista.forEach(System.out::println);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Text blocks para strings multilínea
|
|
194
|
+
|
|
195
|
+
```java
|
|
196
|
+
// MAL — concatenacion fragil
|
|
197
|
+
String sql = "SELECT u.id, u.nombre " +
|
|
198
|
+
"FROM usuarios u " +
|
|
199
|
+
"WHERE u.activo = true " +
|
|
200
|
+
"ORDER BY u.nombre";
|
|
201
|
+
|
|
202
|
+
// BIEN — text block (Java 15+)
|
|
203
|
+
String sql = """
|
|
204
|
+
SELECT u.id, u.nombre
|
|
205
|
+
FROM usuarios u
|
|
206
|
+
WHERE u.activo = true
|
|
207
|
+
ORDER BY u.nombre
|
|
208
|
+
""";
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Anti-patrones conocidos
|
|
212
|
+
|
|
213
|
+
### Stringly-typed — NUNCA usar String para conceptos de dominio
|
|
214
|
+
|
|
215
|
+
```java
|
|
216
|
+
// MAL — cualquier String pasa sin verificacion
|
|
217
|
+
void transferir(String cuentaOrigen, String cuentaDestino, double monto) { ... }
|
|
218
|
+
|
|
219
|
+
// BIEN — tipos que documentan y verifican en compilacion
|
|
220
|
+
void transferir(CuentaId origen, CuentaId destino, Dinero monto) { ... }
|
|
221
|
+
|
|
222
|
+
public record CuentaId(String valor) {
|
|
223
|
+
public CuentaId { Objects.requireNonNull(valor); }
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### null en colecciones o retornos de lista
|
|
228
|
+
|
|
229
|
+
```java
|
|
230
|
+
// MAL — NullPointerException silencioso en el llamador
|
|
231
|
+
public List<Pedido> buscarActivos() {
|
|
232
|
+
if (cache.isEmpty()) return null; // obliga al llamador a chequear null
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// BIEN — coleccion vacia explicita
|
|
236
|
+
public List<Pedido> buscarActivos() {
|
|
237
|
+
if (cache.isEmpty()) return List.of();
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### instanceof encadenados en lugar de sealed + switch
|
|
242
|
+
|
|
243
|
+
```java
|
|
244
|
+
// MAL — fragil y no exhaustivo
|
|
245
|
+
if (evento instanceof EventoPedidoCreado) { ... }
|
|
246
|
+
else if (evento instanceof EventoPedidoCancelado) { ... }
|
|
247
|
+
// si se agrega un tercer tipo, el compilador no avisa
|
|
248
|
+
|
|
249
|
+
// BIEN — sealed garantiza exhaustividad
|
|
250
|
+
sealed interface EventoPedido permits EventoPedidoCreado, EventoPedidoCancelado {}
|
|
251
|
+
// switch expression obliga a cubrir todos los casos
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Checklist de verificación
|
|
255
|
+
|
|
256
|
+
- [ ] Value objects usan record, no POJO mutable
|
|
257
|
+
- [ ] Optional solo como tipo de retorno, nunca como parámetro
|
|
258
|
+
- [ ] Dominios cerrados usan sealed interface con switch exhaustivo
|
|
259
|
+
- [ ] No hay instanceof encadenados: se usan patterns o polimorfismo
|
|
260
|
+
- [ ] Ordenamientos usan Comparator.comparing, no Comparable en DTOs
|
|
261
|
+
- [ ] Sin null como retorno de colecciones: usar List.of() o Collections.emptyList()
|
|
262
|
+
- [ ] Text blocks para strings multilínea de más de 2 líneas
|
|
263
|
+
|
|
264
|
+
## Gotchas / Errores comunes no obvios
|
|
265
|
+
|
|
266
|
+
**Sealed interface con `permits` en módulo diferente al subtype requiere el mismo paquete**: las clases/interfaces que implementan un sealed interface deben estar en el mismo paquete o módulo que el sealed type. Si se intenta implementar en un paquete diferente del mismo proyecto, el compilador lanza error aunque el paquete sea accesible. Fix: colocar las implementaciones permitidas en el mismo paquete que el sealed interface, o usar JPMS para permitir acceso explícito.
|
|
267
|
+
|
|
268
|
+
**`record` con campo de tipo mutable (List, Map) no es immutable de verdad**: `record Pedido(List<Item> items)` compila pero `pedido.items().add(new Item(...))` muta el estado interno. La naturaleza final de los campos del record solo impide reasignación de la referencia, no mutación del objeto apuntado. Fix: usar `List.copyOf(items)` en el canonical constructor o retornar `Collections.unmodifiableList` en el accessor.
|
|
269
|
+
|
|
270
|
+
**`switch` expression exhaustivo con `default` no detecta casos olvidados en sealed types**: si se agrega un nuevo subtipo a una sealed interface, un `switch` con `default ->` compila sin error pero el nuevo caso cae al default silenciosamente. Fix: usar `switch` sin `default` en dominios sellados — el compilador fuerza entonces la adición del caso nuevo como error de compilación (solo funciona con sealed types).
|
|
271
|
+
|
|
272
|
+
**`Optional` como campo de entidad JPA causa serialización inconsistente**: persistir `Optional<String>` como campo de una entidad JPA causa problemas con proveedores de persistencia que no reconocen `Optional` como tipo persistible. Fix: nunca usar `Optional` como tipo de campo de entidad; usar `String` (nullable) en la entidad y envolver con `Optional` solo en el valor de retorno del repositorio o service.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: java-testing
|
|
3
|
+
description: >
|
|
4
|
+
Testing Java con JUnit 5, Mockito, TestContainers y AssertJ. Cubre tests
|
|
5
|
+
unitarios, de integración con base de datos real y slices de Spring Boot.
|
|
6
|
+
Cargar cuando se escriban tests en Java o se configure JaCoCo.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
herramientasPermitidas: [Read, Grep]
|
|
9
|
+
exclusiones:
|
|
10
|
+
- "No cargar para implementar el código de producción que se va a testear — primero implementar con `java-experto`, luego escribir tests."
|
|
11
|
+
- "No cargar para diseñar patrones Java modernos — para diseño cargar `java-patrones`."
|
|
12
|
+
- "No cargar para errores de compilación Java o Gradle en los tests — para build errors cargar `build-errors-java`."
|
|
13
|
+
- "No cargar para tests Kotlin/Android — Kotlin tiene su propio ecosistema (MockK, Turbine, runTest); cargar `kotlin-testing`."
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
---
|
|
16
|
+
# Java Testing — JUnit 5, Mockito y TestContainers
|
|
17
|
+
|
|
18
|
+
Cubre el ecosistema de testing Java moderno: JUnit 5 con lifecycle y tests
|
|
19
|
+
parametrizados, Mockito para mocks, TestContainers para infraestructura real,
|
|
20
|
+
slices de Spring Boot y cobertura con JaCoCo.
|
|
21
|
+
|
|
22
|
+
## Cuándo cargar este skill
|
|
23
|
+
|
|
24
|
+
Invoca `Skill("java-testing")` cuando:
|
|
25
|
+
|
|
26
|
+
- Se escriban tests unitarios para services, domain objects o utilities Java
|
|
27
|
+
- Se escriban tests de integración con base de datos (PostgreSQL, MySQL, Redis)
|
|
28
|
+
- Se testeen controllers con MockMvc o WebTestClient
|
|
29
|
+
- Se configure JaCoCo para reporte de cobertura
|
|
30
|
+
- Se usen @SpringBootTest, @WebMvcTest o @DataJpaTest
|
|
31
|
+
|
|
32
|
+
## Cuándo NO cargar
|
|
33
|
+
|
|
34
|
+
- El código de producción aún no existe — primero implementar con `java-experto`, luego escribir tests.
|
|
35
|
+
- La pregunta es sobre diseño de patrones Java modernos — cargar `java-patrones`.
|
|
36
|
+
- Los errores son de compilación Java o Gradle en los archivos de test — cargar `build-errors-java`.
|
|
37
|
+
- Los tests son para un proyecto Kotlin/Android — Kotlin tiene su propio ecosistema de testing (MockK, Turbine, runTest); cargar `kotlin-testing`.
|
|
38
|
+
|
|
39
|
+
## Conceptos clave
|
|
40
|
+
|
|
41
|
+
### Slices de Spring Boot
|
|
42
|
+
|
|
43
|
+
Cada slice levanta solo la capa necesaria, acelerando los tests:
|
|
44
|
+
- `@WebMvcTest`: carga solo la capa web (controllers, filtros, serialization)
|
|
45
|
+
- `@DataJpaTest`: carga solo JPA, usa H2 por defecto o TestContainers
|
|
46
|
+
- `@SpringBootTest`: levanta todo el contexto; usar solo para tests E2E
|
|
47
|
+
|
|
48
|
+
### TestContainers
|
|
49
|
+
|
|
50
|
+
Lanza contenedores Docker reales durante los tests. Garantiza que el test
|
|
51
|
+
usa la misma versión del motor de BD que producción, eliminando diferencias
|
|
52
|
+
con H2 embebido.
|
|
53
|
+
|
|
54
|
+
### AssertJ
|
|
55
|
+
|
|
56
|
+
API fluida de assertions que produce mensajes de error descriptivos y permite
|
|
57
|
+
encadenar verificaciones sobre el mismo objeto sin repetir el subject.
|
|
58
|
+
|
|
59
|
+
## Reglas obligatorias
|
|
60
|
+
|
|
61
|
+
### Un solo comportamiento por test — nombre descriptivo
|
|
62
|
+
|
|
63
|
+
Un test verifica un solo comportamiento. El nombre documenta el escenario:
|
|
64
|
+
`dado_[precondicion]_cuando_[accion]_entonces_[resultado]` o su equivalente
|
|
65
|
+
en inglés `should_[resultado]_when_[condicion]`.
|
|
66
|
+
|
|
67
|
+
### Mockito: verificar comportamiento, no implementación
|
|
68
|
+
|
|
69
|
+
`verify()` solo para efectos secundarios observables (envío de email, publicación
|
|
70
|
+
de evento). No verificar cada llamada interna — eso acopla el test a la implementación.
|
|
71
|
+
|
|
72
|
+
### TestContainers con @Container estático para reutilizar
|
|
73
|
+
|
|
74
|
+
Instanciar el contenedor como `static` reutiliza el mismo contenedor en todos
|
|
75
|
+
los tests de la clase, evitando arranques lentos repetidos.
|
|
76
|
+
|
|
77
|
+
### AssertJ sobre assertions nativas de JUnit
|
|
78
|
+
|
|
79
|
+
`assertThat(resultado).isEqualTo(esperado)` produce mensajes de error con el
|
|
80
|
+
valor actual y esperado. `assertEquals(esperado, actual)` de JUnit no.
|
|
81
|
+
|
|
82
|
+
## Patrones recomendados
|
|
83
|
+
|
|
84
|
+
### Test unitario con Mockito (AAA)
|
|
85
|
+
|
|
86
|
+
```java
|
|
87
|
+
@ExtendWith(MockitoExtension.class)
|
|
88
|
+
class PedidoServiceTest {
|
|
89
|
+
|
|
90
|
+
@Mock PedidoRepository repo;
|
|
91
|
+
@Mock EventoPublisher publisher;
|
|
92
|
+
@InjectMocks PedidoService service;
|
|
93
|
+
|
|
94
|
+
@Test
|
|
95
|
+
void deberiaPublicarEventoCuandoPedidoConfirmado() {
|
|
96
|
+
// Arrange
|
|
97
|
+
var pedido = PedidoFactory.unPedidoBorrador();
|
|
98
|
+
when(repo.findById(pedido.getId())).thenReturn(Optional.of(pedido));
|
|
99
|
+
when(repo.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
100
|
+
|
|
101
|
+
// Act
|
|
102
|
+
service.confirmar(pedido.getId());
|
|
103
|
+
|
|
104
|
+
// Assert
|
|
105
|
+
var captor = ArgumentCaptor.forClass(PedidoConfirmadoEvento.class);
|
|
106
|
+
verify(publisher).publicar(captor.capture());
|
|
107
|
+
assertThat(captor.getValue().pedidoId()).isEqualTo(pedido.getId());
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Test parametrizado con @ParameterizedTest
|
|
113
|
+
|
|
114
|
+
```java
|
|
115
|
+
@ParameterizedTest(name = "precio={0}, cantidad={1}, esperado={2}")
|
|
116
|
+
@CsvSource({
|
|
117
|
+
"100.0, 2, 200.0",
|
|
118
|
+
"50.5, 3, 151.5",
|
|
119
|
+
"0.0, 5, 0.0"
|
|
120
|
+
})
|
|
121
|
+
void deberiaCalcularTotalCorrectamente(double precio, int cantidad, double esperado) {
|
|
122
|
+
var item = new ItemPedido(UUID.randomUUID(), precio, cantidad);
|
|
123
|
+
assertThat(item.total()).isEqualTo(esperado);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### @Nested para agrupar escenarios relacionados
|
|
128
|
+
|
|
129
|
+
```java
|
|
130
|
+
class PedidoServiceTest {
|
|
131
|
+
|
|
132
|
+
@Nested
|
|
133
|
+
class CuandoPedidoExiste {
|
|
134
|
+
@Test void deberiaConfirmar() { ... }
|
|
135
|
+
@Test void deberiaCancelar() { ... }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@Nested
|
|
139
|
+
class CuandoPedidoNoExiste {
|
|
140
|
+
@Test void deberiaLanzarNotFoundException() { ... }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### TestContainers con @DataJpaTest
|
|
146
|
+
|
|
147
|
+
```java
|
|
148
|
+
@DataJpaTest
|
|
149
|
+
@AutoConfigureTestDatabase(replace = Replace.NONE)
|
|
150
|
+
@Testcontainers
|
|
151
|
+
class PedidoRepositoryTest {
|
|
152
|
+
|
|
153
|
+
@Container
|
|
154
|
+
static PostgreSQLContainer<?> postgres =
|
|
155
|
+
new PostgreSQLContainer<>("postgres:16-alpine");
|
|
156
|
+
|
|
157
|
+
@DynamicPropertySource
|
|
158
|
+
static void configurarDatasource(DynamicPropertyRegistry registry) {
|
|
159
|
+
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
160
|
+
registry.add("spring.datasource.username", postgres::getUsername);
|
|
161
|
+
registry.add("spring.datasource.password", postgres::getPassword);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@Autowired PedidoRepository repo;
|
|
165
|
+
|
|
166
|
+
@Test
|
|
167
|
+
void deberiaEncontrarPedidosPorClienteId() {
|
|
168
|
+
var pedido = repo.save(PedidoFactory.unPedido());
|
|
169
|
+
var resultado = repo.findByClienteId(pedido.getClienteId());
|
|
170
|
+
assertThat(resultado).hasSize(1)
|
|
171
|
+
.first().extracting(Pedido::getId).isEqualTo(pedido.getId());
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### MockMvc para tests de controller
|
|
177
|
+
|
|
178
|
+
```java
|
|
179
|
+
@WebMvcTest(PedidoController.class)
|
|
180
|
+
class PedidoControllerTest {
|
|
181
|
+
|
|
182
|
+
@Autowired MockMvc mvc;
|
|
183
|
+
@MockBean PedidoService service;
|
|
184
|
+
|
|
185
|
+
@Test
|
|
186
|
+
void deberiaRetornar201CuandoPedidoCreadoCorrectamente() throws Exception {
|
|
187
|
+
var response = new PedidoResponse(UUID.randomUUID(), "Cliente X", List.of());
|
|
188
|
+
when(service.crear(any())).thenReturn(response);
|
|
189
|
+
|
|
190
|
+
mvc.perform(post("/v1/pedidos")
|
|
191
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
192
|
+
.content("""
|
|
193
|
+
{"clienteId": "some-uuid", "items": []}
|
|
194
|
+
"""))
|
|
195
|
+
.andExpect(status().isCreated())
|
|
196
|
+
.andExpect(jsonPath("$.id").exists());
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Configuracion JaCoCo en build.gradle
|
|
202
|
+
|
|
203
|
+
```groovy
|
|
204
|
+
jacocoTestReport {
|
|
205
|
+
dependsOn test
|
|
206
|
+
reports { xml.required = true }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
jacocoTestCoverageVerification {
|
|
210
|
+
violationRules {
|
|
211
|
+
rule {
|
|
212
|
+
limit {
|
|
213
|
+
minimum = 0.80 // 80% minimo en lineas
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
check.dependsOn jacocoTestCoverageVerification
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Anti-patrones conocidos
|
|
223
|
+
|
|
224
|
+
### Thread.sleep en tests — NUNCA hacer esto
|
|
225
|
+
|
|
226
|
+
```java
|
|
227
|
+
// MAL — lento y no determinista
|
|
228
|
+
Thread.sleep(2000);
|
|
229
|
+
assertThat(resultado).isNotNull();
|
|
230
|
+
|
|
231
|
+
// BIEN — Awaitility para condiciones asincronas
|
|
232
|
+
await().atMost(5, SECONDS)
|
|
233
|
+
.untilAsserted(() -> assertThat(repo.findById(id)).isPresent());
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### @SpringBootTest cuando basta un slice
|
|
237
|
+
|
|
238
|
+
```java
|
|
239
|
+
// MAL — levanta todo el contexto para testear un solo controller
|
|
240
|
+
@SpringBootTest
|
|
241
|
+
@AutoConfigureMockMvc
|
|
242
|
+
class PedidoControllerTest { ... }
|
|
243
|
+
|
|
244
|
+
// BIEN — solo la capa web
|
|
245
|
+
@WebMvcTest(PedidoController.class)
|
|
246
|
+
class PedidoControllerTest { ... }
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Verify en flujos normales de lectura
|
|
250
|
+
|
|
251
|
+
```java
|
|
252
|
+
// MAL — verifica implementacion, no comportamiento
|
|
253
|
+
verify(repo, times(1)).findById(id);
|
|
254
|
+
verify(mapper, times(1)).toResponse(any());
|
|
255
|
+
|
|
256
|
+
// BIEN — solo verificar el resultado observable
|
|
257
|
+
assertThat(response.id()).isEqualTo(esperadoId);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Checklist de verificación
|
|
261
|
+
|
|
262
|
+
- [ ] Cada test verifica un solo comportamiento con nombre descriptivo
|
|
263
|
+
- [ ] @DataJpaTest con TestContainers, no con H2 embebido
|
|
264
|
+
- [ ] @WebMvcTest para controllers; @SpringBootTest solo para E2E
|
|
265
|
+
- [ ] AssertJ en todas las assertions (no assertEquals de JUnit)
|
|
266
|
+
- [ ] Sin Thread.sleep: usar Awaitility para condiciones asíncronas
|
|
267
|
+
- [ ] JaCoCo configurado con umbral mínimo del 80%
|
|
268
|
+
- [ ] verify() solo para efectos secundarios, no para flujos de lectura
|
|
269
|
+
|
|
270
|
+
## Referencias
|
|
271
|
+
|
|
272
|
+
- JUnit 5 User Guide: https://junit.org/junit5/docs/current/user-guide/
|
|
273
|
+
- Mockito Docs: https://javadoc.io/doc/org.mockito/mockito-core/latest/
|
|
274
|
+
- TestContainers Java: https://java.testcontainers.org/
|
|
275
|
+
- AssertJ Docs: https://assertj.github.io/doc/
|
|
276
|
+
|
|
277
|
+
## Gotchas / Errores comunes no obvios
|
|
278
|
+
|
|
279
|
+
**`@MockBean` recrea el contexto de Spring en cada clase de test que lo usa**: cada clase de test con `@MockBean` distinto genera un `ApplicationContext` nuevo, aumentando el tiempo total de la suite de forma exponencial. Causa: Spring cachea el contexto solo si la configuración es idéntica entre clases. Fix: consolidar los mocks en una clase base abstracta con `@MockBean` compartida, o usar `@SpyBean` con un bean real cuando sea posible para evitar recrear el contexto.
|
|
280
|
+
|
|
281
|
+
**TestContainers con `@DynamicPropertySource` no limpia el datasource entre tests de la misma JVM**: si múltiples clases de test usan `@DynamicPropertySource` con TestContainers, los datos de un test pueden contaminar el siguiente si no se truncan las tablas en `@AfterEach`. Causa: el container reutilizado no se reinicia entre clases. Fix: usar `@Transactional` en los tests de integración (Spring lo rollbackea), o implementar `@AfterEach` que ejecuta `TRUNCATE TABLE ... CASCADE`.
|
|
282
|
+
|
|
283
|
+
**`verify(mock).metodo(...)` con `ArgumentCaptor` captura la referencia mutable, no el valor**: si el argumento capturado es una lista que se modifica después de la llamada al mock, el `captor.getValue()` refleja el estado final modificado, no el estado en el momento de la llamada. Fix: capturar y convertir a una copia inmutable inmediatamente: `List<T> captured = List.copyOf(captor.getValue())`.
|
|
284
|
+
|
|
285
|
+
**`@DataJpaTest` no carga `@Service` ni `@Component` — solo la capa JPA**: un test con `@DataJpaTest` que intenta inyectar un service o usar beans de negocio falla con `NoSuchBeanDefinitionException`. Causa: `@DataJpaTest` configura un slice mínimo con solo repositorios y el EntityManager. Fix: usar `@SpringBootTest(webEnvironment = NONE)` para tests de integración que necesiten el contexto completo, o anotar los beans adicionales con `@Import(MiService.class)`.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
|