aigroup-workflow 2.2.1 → 2.2.2
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/commands/fix-build.md +10 -5
- package/.claude/commands/init-project.md +13 -8
- package/.claude/commands/plan.md +15 -8
- package/.claude/commands/review.md +12 -6
- package/.claude/commands/tdd.md +11 -5
- package/.claude/commands/workflow-start.md +20 -11
- package/.claude/settings.json +28 -0
- package/.codex/agents/architect.toml +207 -0
- package/.codex/agents/build-error-resolver.toml +110 -0
- package/.codex/agents/code-reviewer.toml +233 -0
- package/.codex/agents/doc-updater.toml +103 -0
- package/.codex/agents/e2e-runner.toml +103 -0
- package/.codex/agents/get-current-datetime.toml +23 -0
- package/.codex/agents/init-architect.toml +181 -0
- package/.codex/agents/planner.toml +208 -0
- package/.codex/agents/refactor-cleaner.toml +81 -0
- package/.codex/agents/rust-reviewer.toml +90 -0
- package/.codex/agents/security-reviewer.toml +104 -0
- package/.codex/agents/tdd-guide.toml +87 -0
- package/AGENTS.md +2 -2
- package/CLAUDE.md +23 -1
- package/LICENSE +20 -20
- package/README.md +333 -333
- package/agents/a11y-architect.md +141 -141
- package/agents/architect.md +211 -211
- package/agents/build-error-resolver.md +114 -114
- package/agents/chief-of-staff.md +151 -151
- package/agents/code-architect.md +71 -71
- package/agents/code-explorer.md +69 -69
- package/agents/code-reviewer.md +237 -237
- package/agents/code-simplifier.md +47 -47
- package/agents/comment-analyzer.md +45 -45
- package/agents/conversation-analyzer.md +52 -52
- package/agents/cpp-build-resolver.md +90 -90
- package/agents/cpp-reviewer.md +72 -72
- package/agents/csharp-reviewer.md +101 -101
- package/agents/dart-build-resolver.md +201 -201
- package/agents/database-reviewer.md +91 -91
- package/agents/doc-updater.md +107 -107
- package/agents/docs-lookup.md +68 -68
- package/agents/e2e-runner.md +107 -107
- package/agents/flutter-reviewer.md +243 -243
- package/agents/gan-evaluator.md +209 -209
- package/agents/gan-generator.md +131 -131
- package/agents/gan-planner.md +99 -99
- package/agents/get-current-datetime.md +26 -26
- package/agents/go-build-resolver.md +94 -94
- package/agents/go-reviewer.md +76 -76
- package/agents/harness-optimizer.md +35 -35
- package/agents/healthcare-reviewer.md +83 -83
- package/agents/java-build-resolver.md +153 -153
- package/agents/java-reviewer.md +92 -92
- package/agents/kotlin-build-resolver.md +118 -118
- package/agents/kotlin-reviewer.md +159 -159
- package/agents/loop-operator.md +36 -36
- package/agents/opensource-forker.md +198 -198
- package/agents/opensource-packager.md +249 -249
- package/agents/opensource-sanitizer.md +188 -188
- package/agents/performance-optimizer.md +446 -446
- package/agents/planner.md +212 -212
- package/agents/pr-test-analyzer.md +45 -45
- package/agents/python-reviewer.md +98 -98
- package/agents/pytorch-build-resolver.md +120 -120
- package/agents/refactor-cleaner.md +85 -85
- package/agents/rust-build-resolver.md +148 -148
- package/agents/rust-reviewer.md +94 -94
- package/agents/security-reviewer.md +108 -108
- package/agents/seo-specialist.md +59 -59
- package/agents/silent-failure-hunter.md +50 -50
- package/agents/tdd-guide.md +91 -91
- package/agents/type-design-analyzer.md +41 -41
- package/agents/typescript-reviewer.md +112 -112
- package/cli/commands/update.mjs +1 -1
- package/cli/utils/scaffold.mjs +53 -0
- package/docs/rules/agents.md +166 -50
- package/docs/rules/cpp/coding-style.md +44 -44
- package/docs/rules/cpp/hooks.md +39 -39
- package/docs/rules/cpp/patterns.md +51 -51
- package/docs/rules/cpp/security.md +51 -51
- package/docs/rules/cpp/testing.md +44 -44
- package/docs/rules/csharp/coding-style.md +72 -72
- package/docs/rules/csharp/hooks.md +25 -25
- package/docs/rules/csharp/patterns.md +50 -50
- package/docs/rules/csharp/security.md +58 -58
- package/docs/rules/csharp/testing.md +46 -46
- package/docs/rules/dart/coding-style.md +159 -159
- package/docs/rules/dart/hooks.md +66 -66
- package/docs/rules/dart/patterns.md +261 -261
- package/docs/rules/dart/security.md +135 -135
- package/docs/rules/dart/testing.md +215 -215
- package/docs/rules/golang/coding-style.md +32 -32
- package/docs/rules/golang/hooks.md +17 -17
- package/docs/rules/golang/patterns.md +45 -45
- package/docs/rules/golang/security.md +34 -34
- package/docs/rules/golang/testing.md +31 -31
- package/docs/rules/java/coding-style.md +114 -114
- package/docs/rules/java/hooks.md +18 -18
- package/docs/rules/java/patterns.md +146 -146
- package/docs/rules/java/security.md +100 -100
- package/docs/rules/java/testing.md +131 -131
- package/docs/rules/kotlin/coding-style.md +86 -86
- package/docs/rules/kotlin/hooks.md +17 -17
- package/docs/rules/kotlin/patterns.md +146 -146
- package/docs/rules/kotlin/security.md +82 -82
- package/docs/rules/kotlin/testing.md +128 -128
- package/docs/rules/perl/coding-style.md +46 -46
- package/docs/rules/perl/hooks.md +22 -22
- package/docs/rules/perl/patterns.md +76 -76
- package/docs/rules/perl/security.md +69 -69
- package/docs/rules/perl/testing.md +54 -54
- package/docs/rules/php/coding-style.md +40 -40
- package/docs/rules/php/hooks.md +24 -24
- package/docs/rules/php/patterns.md +33 -33
- package/docs/rules/php/security.md +37 -37
- package/docs/rules/php/testing.md +39 -39
- package/docs/rules/python/coding-style.md +42 -42
- package/docs/rules/python/hooks.md +19 -19
- package/docs/rules/python/patterns.md +39 -39
- package/docs/rules/python/security.md +30 -30
- package/docs/rules/python/testing.md +38 -38
- package/docs/rules/rust/coding-style.md +151 -151
- package/docs/rules/rust/hooks.md +16 -16
- package/docs/rules/rust/patterns.md +168 -168
- package/docs/rules/rust/security.md +141 -141
- package/docs/rules/rust/testing.md +154 -154
- package/docs/rules/swift/coding-style.md +47 -47
- package/docs/rules/swift/hooks.md +20 -20
- package/docs/rules/swift/patterns.md +66 -66
- package/docs/rules/swift/security.md +33 -33
- package/docs/rules/swift/testing.md +45 -45
- package/docs/rules/typescript/coding-style.md +199 -199
- package/docs/rules/typescript/hooks.md +22 -22
- package/docs/rules/typescript/patterns.md +52 -52
- package/docs/rules/typescript/security.md +28 -28
- package/docs/rules/typescript/testing.md +18 -18
- package/docs/rules/web/coding-style.md +96 -96
- package/docs/rules/web/design-quality.md +62 -62
- package/docs/rules/web/hooks.md +120 -120
- package/docs/rules/web/patterns.md +79 -79
- package/docs/rules/web/performance.md +64 -64
- package/docs/rules/web/security.md +57 -57
- package/docs/rules/web/testing.md +55 -55
- package/docs/templates/README.md +36 -36
- package/docs/templates/ai-project-final.md +124 -124
- package/docs/templates/ai-project.md +105 -105
- package/docs/templates/api.md +157 -157
- package/docs/templates/bug.md +62 -62
- package/docs/templates/code-review.md +87 -87
- package/docs/templates/generic.md +116 -116
- package/docs/templates/implementation-plan.md +1 -1
- package/docs/templates/meeting.md +68 -68
- package/docs/templates/prd.md +98 -98
- package/docs/templates/ui.md +134 -134
- package/docs/workflow-pipeline.md +5 -5
- package/package.json +40 -39
- package/skills/SUPERPOWERS-LICENSE +21 -21
- package/skills/ai-ml/fine-tuning-expert/SKILL.md +162 -162
- package/skills/ai-ml/fine-tuning-expert/references/dataset-preparation.md +540 -540
- package/skills/ai-ml/fine-tuning-expert/references/deployment-optimization.md +673 -673
- package/skills/ai-ml/fine-tuning-expert/references/evaluation-metrics.md +597 -597
- package/skills/ai-ml/fine-tuning-expert/references/hyperparameter-tuning.md +565 -565
- package/skills/ai-ml/fine-tuning-expert/references/lora-peft.md +347 -347
- package/skills/ai-ml/ml-pipeline/SKILL.md +159 -159
- package/skills/ai-ml/ml-pipeline/references/experiment-tracking.md +833 -833
- package/skills/ai-ml/ml-pipeline/references/feature-engineering.md +631 -631
- package/skills/ai-ml/ml-pipeline/references/model-validation.md +978 -978
- package/skills/ai-ml/ml-pipeline/references/pipeline-orchestration.md +907 -907
- package/skills/ai-ml/ml-pipeline/references/training-pipelines.md +782 -782
- package/skills/ai-ml/rag-architect/SKILL.md +194 -194
- package/skills/ai-ml/rag-architect/references/chunking-strategies.md +878 -878
- package/skills/ai-ml/rag-architect/references/embedding-models.md +561 -561
- package/skills/ai-ml/rag-architect/references/rag-evaluation.md +833 -833
- package/skills/ai-ml/rag-architect/references/retrieval-optimization.md +795 -795
- package/skills/ai-ml/rag-architect/references/vector-databases.md +589 -589
- package/skills/ai-ml/spark-engineer/SKILL.md +148 -148
- package/skills/ai-ml/spark-engineer/references/partitioning-caching.md +543 -543
- package/skills/ai-ml/spark-engineer/references/performance-tuning.md +544 -544
- package/skills/ai-ml/spark-engineer/references/rdd-operations.md +599 -599
- package/skills/ai-ml/spark-engineer/references/spark-sql-dataframes.md +474 -474
- package/skills/ai-ml/spark-engineer/references/streaming-patterns.md +786 -786
- package/skills/backend/api-designer/SKILL.md +217 -217
- package/skills/backend/api-designer/references/error-handling.md +541 -541
- package/skills/backend/api-designer/references/openapi.md +824 -824
- package/skills/backend/api-designer/references/pagination.md +494 -494
- package/skills/backend/api-designer/references/rest-patterns.md +335 -335
- package/skills/backend/api-designer/references/versioning.md +391 -391
- package/skills/backend/architecture-designer/SKILL.md +117 -117
- package/skills/backend/architecture-designer/references/adr-template.md +116 -116
- package/skills/backend/architecture-designer/references/architecture-patterns.md +111 -111
- package/skills/backend/architecture-designer/references/database-selection.md +102 -102
- package/skills/backend/architecture-designer/references/nfr-checklist.md +112 -112
- package/skills/backend/architecture-designer/references/system-design.md +100 -100
- package/skills/backend/code-documenter/SKILL.md +147 -147
- package/skills/backend/code-documenter/references/api-docs-fastapi-django.md +166 -166
- package/skills/backend/code-documenter/references/api-docs-nestjs-express.md +220 -220
- package/skills/backend/code-documenter/references/coverage-reports.md +125 -125
- package/skills/backend/code-documenter/references/documentation-systems.md +333 -333
- package/skills/backend/code-documenter/references/interactive-api-docs.md +531 -531
- package/skills/backend/code-documenter/references/python-docstrings.md +121 -121
- package/skills/backend/code-documenter/references/typescript-jsdoc.md +145 -145
- package/skills/backend/code-documenter/references/user-guides-tutorials.md +530 -530
- package/skills/backend/debugging-wizard/SKILL.md +105 -105
- package/skills/backend/debugging-wizard/references/common-patterns.md +132 -132
- package/skills/backend/debugging-wizard/references/debugging-tools.md +140 -140
- package/skills/backend/debugging-wizard/references/quick-fixes.md +177 -177
- package/skills/backend/debugging-wizard/references/strategies.md +142 -142
- package/skills/backend/debugging-wizard/references/systematic-debugging.md +367 -367
- package/skills/backend/feature-forge/SKILL.md +98 -98
- package/skills/backend/feature-forge/references/acceptance-criteria.md +104 -104
- package/skills/backend/feature-forge/references/ears-syntax.md +99 -99
- package/skills/backend/feature-forge/references/interview-questions.md +150 -150
- package/skills/backend/feature-forge/references/pre-discovery-subagents.md +54 -54
- package/skills/backend/feature-forge/references/specification-template.md +103 -103
- package/skills/backend/fullstack-guardian/SKILL.md +105 -105
- package/skills/backend/fullstack-guardian/references/api-design-standards.md +307 -307
- package/skills/backend/fullstack-guardian/references/architecture-decisions.md +350 -350
- package/skills/backend/fullstack-guardian/references/backend-patterns.md +237 -237
- package/skills/backend/fullstack-guardian/references/common-patterns.md +134 -134
- package/skills/backend/fullstack-guardian/references/deliverables-checklist.md +354 -354
- package/skills/backend/fullstack-guardian/references/design-template.md +91 -91
- package/skills/backend/fullstack-guardian/references/error-handling.md +135 -135
- package/skills/backend/fullstack-guardian/references/frontend-patterns.md +340 -340
- package/skills/backend/fullstack-guardian/references/integration-patterns.md +333 -333
- package/skills/backend/fullstack-guardian/references/security-checklist.md +106 -106
- package/skills/backend/graphql-architect/SKILL.md +146 -146
- package/skills/backend/graphql-architect/references/federation.md +418 -418
- package/skills/backend/graphql-architect/references/migration-from-rest.md +1141 -1141
- package/skills/backend/graphql-architect/references/resolvers.md +425 -425
- package/skills/backend/graphql-architect/references/schema-design.md +393 -393
- package/skills/backend/graphql-architect/references/security.md +569 -569
- package/skills/backend/graphql-architect/references/subscriptions.md +510 -510
- package/skills/backend/legacy-modernizer/SKILL.md +137 -137
- package/skills/backend/legacy-modernizer/references/legacy-testing.md +381 -381
- package/skills/backend/legacy-modernizer/references/migration-strategies.md +423 -423
- package/skills/backend/legacy-modernizer/references/refactoring-patterns.md +395 -395
- package/skills/backend/legacy-modernizer/references/strangler-fig-pattern.md +281 -281
- package/skills/backend/legacy-modernizer/references/system-assessment.md +487 -487
- package/skills/backend/microservices-architect/SKILL.md +164 -164
- package/skills/backend/microservices-architect/references/communication.md +499 -499
- package/skills/backend/microservices-architect/references/data.md +721 -721
- package/skills/backend/microservices-architect/references/decomposition.md +344 -344
- package/skills/backend/microservices-architect/references/observability.md +805 -805
- package/skills/backend/microservices-architect/references/patterns.md +603 -603
- package/skills/database/database-optimizer/SKILL.md +147 -147
- package/skills/database/database-optimizer/references/index-strategies.md +331 -331
- package/skills/database/database-optimizer/references/monitoring-analysis.md +501 -501
- package/skills/database/database-optimizer/references/mysql-tuning.md +452 -452
- package/skills/database/database-optimizer/references/postgresql-tuning.md +413 -413
- package/skills/database/database-optimizer/references/query-optimization.md +251 -251
- package/skills/database/postgres-pro/SKILL.md +152 -152
- package/skills/database/postgres-pro/references/extensions.md +404 -404
- package/skills/database/postgres-pro/references/jsonb.md +321 -321
- package/skills/database/postgres-pro/references/maintenance.md +481 -481
- package/skills/database/postgres-pro/references/performance.md +265 -265
- package/skills/database/postgres-pro/references/replication.md +446 -446
- package/skills/database/sql-pro/SKILL.md +129 -129
- package/skills/database/sql-pro/references/database-design.md +402 -402
- package/skills/database/sql-pro/references/dialect-differences.md +419 -419
- package/skills/database/sql-pro/references/optimization.md +384 -384
- package/skills/database/sql-pro/references/query-patterns.md +285 -285
- package/skills/database/sql-pro/references/window-functions.md +328 -328
- package/skills/dotnet/csharp-developer/SKILL.md +125 -125
- package/skills/dotnet/csharp-developer/references/aspnet-core.md +394 -394
- package/skills/dotnet/csharp-developer/references/blazor.md +553 -553
- package/skills/dotnet/csharp-developer/references/entity-framework.md +409 -409
- package/skills/dotnet/csharp-developer/references/modern-csharp.md +248 -248
- package/skills/dotnet/csharp-developer/references/performance.md +498 -498
- package/skills/dotnet/dotnet-core-expert/SKILL.md +138 -138
- package/skills/dotnet/dotnet-core-expert/references/authentication.md +546 -546
- package/skills/dotnet/dotnet-core-expert/references/clean-architecture.md +455 -455
- package/skills/dotnet/dotnet-core-expert/references/cloud-native.md +548 -548
- package/skills/dotnet/dotnet-core-expert/references/entity-framework.md +440 -440
- package/skills/dotnet/dotnet-core-expert/references/minimal-apis.md +319 -319
- package/skills/frontend/angular-architect/SKILL.md +152 -152
- package/skills/frontend/angular-architect/references/components.md +297 -297
- package/skills/frontend/angular-architect/references/ngrx.md +401 -401
- package/skills/frontend/angular-architect/references/routing.md +361 -361
- package/skills/frontend/angular-architect/references/rxjs.md +319 -319
- package/skills/frontend/angular-architect/references/testing.md +405 -405
- package/skills/frontend/design-commands/design.md +91 -91
- package/skills/frontend/design-commands/handoff.md +97 -97
- package/skills/frontend/design-commands/prototype.md +120 -120
- package/skills/frontend/design-commands/spec.md +160 -160
- package/skills/frontend/design-commands/style.md +78 -78
- package/skills/frontend/flutter-expert/SKILL.md +138 -138
- package/skills/frontend/flutter-expert/references/bloc-state.md +259 -259
- package/skills/frontend/flutter-expert/references/gorouter-navigation.md +119 -119
- package/skills/frontend/flutter-expert/references/performance.md +99 -99
- package/skills/frontend/flutter-expert/references/project-structure.md +118 -118
- package/skills/frontend/flutter-expert/references/riverpod-state.md +130 -130
- package/skills/frontend/flutter-expert/references/widget-patterns.md +123 -123
- package/skills/frontend/nextjs-developer/SKILL.md +143 -143
- package/skills/frontend/nextjs-developer/references/app-router.md +311 -311
- package/skills/frontend/nextjs-developer/references/data-fetching.md +482 -482
- package/skills/frontend/nextjs-developer/references/deployment.md +545 -545
- package/skills/frontend/nextjs-developer/references/server-actions.md +462 -462
- package/skills/frontend/nextjs-developer/references/server-components.md +384 -384
- package/skills/frontend/react-expert/SKILL.md +149 -149
- package/skills/frontend/react-expert/references/hooks-patterns.md +162 -162
- package/skills/frontend/react-expert/references/migration-class-to-modern.md +1119 -1119
- package/skills/frontend/react-expert/references/performance.md +168 -168
- package/skills/frontend/react-expert/references/react-19-features.md +174 -174
- package/skills/frontend/react-expert/references/server-components.md +143 -143
- package/skills/frontend/react-expert/references/state-management.md +171 -171
- package/skills/frontend/react-expert/references/testing-react.md +174 -174
- package/skills/frontend/react-native-expert/SKILL.md +185 -185
- package/skills/frontend/react-native-expert/references/expo-router.md +187 -187
- package/skills/frontend/react-native-expert/references/list-optimization.md +204 -204
- package/skills/frontend/react-native-expert/references/platform-handling.md +188 -188
- package/skills/frontend/react-native-expert/references/project-structure.md +171 -171
- package/skills/frontend/react-native-expert/references/storage-hooks.md +173 -173
- package/skills/frontend/senior-frontend/SKILL.md +477 -477
- package/skills/frontend/senior-frontend/references/frontend_best_practices.md +806 -806
- package/skills/frontend/senior-frontend/references/nextjs_optimization_guide.md +724 -724
- package/skills/frontend/senior-frontend/references/react_patterns.md +746 -746
- package/skills/frontend/senior-frontend/scripts/bundle_analyzer.py +407 -407
- package/skills/frontend/senior-frontend/scripts/component_generator.py +329 -329
- package/skills/frontend/senior-frontend/scripts/frontend_scaffolder.py +1005 -1005
- package/skills/frontend/ui-ux-pro-max/SKILL.md +386 -386
- package/skills/frontend/ui-ux-pro-max/data/charts.csv +26 -26
- package/skills/frontend/ui-ux-pro-max/data/colors.csv +97 -97
- package/skills/frontend/ui-ux-pro-max/data/icons.csv +101 -101
- package/skills/frontend/ui-ux-pro-max/data/landing.csv +31 -31
- package/skills/frontend/ui-ux-pro-max/data/products.csv +96 -96
- package/skills/frontend/ui-ux-pro-max/data/react-performance.csv +45 -45
- package/skills/frontend/ui-ux-pro-max/data/stacks/astro.csv +54 -54
- package/skills/frontend/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
- package/skills/frontend/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
- package/skills/frontend/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
- package/skills/frontend/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
- package/skills/frontend/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
- package/skills/frontend/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
- package/skills/frontend/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
- package/skills/frontend/ui-ux-pro-max/data/stacks/react.csv +54 -54
- package/skills/frontend/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
- package/skills/frontend/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
- package/skills/frontend/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
- package/skills/frontend/ui-ux-pro-max/data/stacks/vue.csv +50 -50
- package/skills/frontend/ui-ux-pro-max/data/styles.csv +68 -68
- package/skills/frontend/ui-ux-pro-max/data/typography.csv +57 -57
- package/skills/frontend/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
- package/skills/frontend/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
- package/skills/frontend/ui-ux-pro-max/data/web-interface.csv +31 -31
- package/skills/frontend/ui-ux-pro-max/scripts/core.py +253 -253
- package/skills/frontend/ui-ux-pro-max/scripts/design_system.py +1067 -1067
- package/skills/frontend/ui-ux-pro-max/scripts/search.py +114 -114
- package/skills/frontend/vue-expert/SKILL.md +98 -98
- package/skills/frontend/vue-expert/references/build-tooling.md +480 -480
- package/skills/frontend/vue-expert/references/components.md +448 -448
- package/skills/frontend/vue-expert/references/composition-api.md +299 -299
- package/skills/frontend/vue-expert/references/mobile-hybrid.md +636 -636
- package/skills/frontend/vue-expert/references/nuxt.md +669 -669
- package/skills/frontend/vue-expert/references/state-management.md +449 -449
- package/skills/frontend/vue-expert/references/typescript.md +584 -584
- package/skills/frontend/vue-expert-js/SKILL.md +167 -167
- package/skills/frontend/vue-expert-js/references/component-architecture.md +219 -219
- package/skills/frontend/vue-expert-js/references/composables-patterns.md +183 -183
- package/skills/frontend/vue-expert-js/references/jsdoc-typing.md +535 -535
- package/skills/frontend/vue-expert-js/references/state-management.md +249 -249
- package/skills/frontend/vue-expert-js/references/testing-patterns.md +237 -237
- package/skills/go-rust-cpp/cpp-pro/SKILL.md +115 -115
- package/skills/go-rust-cpp/cpp-pro/references/build-tooling.md +440 -440
- package/skills/go-rust-cpp/cpp-pro/references/concurrency.md +437 -437
- package/skills/go-rust-cpp/cpp-pro/references/memory-performance.md +397 -397
- package/skills/go-rust-cpp/cpp-pro/references/modern-cpp.md +304 -304
- package/skills/go-rust-cpp/cpp-pro/references/templates.md +357 -357
- package/skills/go-rust-cpp/golang-pro/SKILL.md +122 -122
- package/skills/go-rust-cpp/golang-pro/references/concurrency.md +329 -329
- package/skills/go-rust-cpp/golang-pro/references/generics.md +442 -442
- package/skills/go-rust-cpp/golang-pro/references/interfaces.md +432 -432
- package/skills/go-rust-cpp/golang-pro/references/project-structure.md +477 -477
- package/skills/go-rust-cpp/golang-pro/references/testing.md +451 -451
- package/skills/go-rust-cpp/rust-engineer/SKILL.md +167 -167
- package/skills/go-rust-cpp/rust-engineer/references/async.md +458 -458
- package/skills/go-rust-cpp/rust-engineer/references/error-handling.md +334 -334
- package/skills/go-rust-cpp/rust-engineer/references/ownership.md +278 -278
- package/skills/go-rust-cpp/rust-engineer/references/testing.md +470 -470
- package/skills/go-rust-cpp/rust-engineer/references/traits.md +413 -413
- package/skills/infra/cli-developer/SKILL.md +113 -113
- package/skills/infra/cli-developer/references/design-patterns.md +221 -221
- package/skills/infra/cli-developer/references/go-cli.md +540 -540
- package/skills/infra/cli-developer/references/node-cli.md +383 -383
- package/skills/infra/cli-developer/references/python-cli.md +422 -422
- package/skills/infra/cli-developer/references/ux-patterns.md +448 -448
- package/skills/infra/cloud-architect/SKILL.md +216 -216
- package/skills/infra/cloud-architect/references/aws.md +394 -394
- package/skills/infra/cloud-architect/references/azure.md +562 -562
- package/skills/infra/cloud-architect/references/cost.md +582 -582
- package/skills/infra/cloud-architect/references/gcp.md +633 -633
- package/skills/infra/cloud-architect/references/multi-cloud.md +483 -483
- package/skills/infra/devops-engineer/SKILL.md +144 -144
- package/skills/infra/devops-engineer/references/deployment-strategies.md +241 -241
- package/skills/infra/devops-engineer/references/docker-patterns.md +113 -113
- package/skills/infra/devops-engineer/references/github-actions.md +139 -139
- package/skills/infra/devops-engineer/references/incident-response.md +331 -331
- package/skills/infra/devops-engineer/references/kubernetes.md +154 -154
- package/skills/infra/devops-engineer/references/platform-engineering.md +417 -417
- package/skills/infra/devops-engineer/references/release-automation.md +527 -527
- package/skills/infra/devops-engineer/references/terraform-iac.md +141 -141
- package/skills/infra/kubernetes-specialist/SKILL.md +241 -241
- package/skills/infra/kubernetes-specialist/references/configuration.md +452 -452
- package/skills/infra/kubernetes-specialist/references/cost-optimization.md +458 -458
- package/skills/infra/kubernetes-specialist/references/custom-operators.md +563 -563
- package/skills/infra/kubernetes-specialist/references/gitops.md +530 -530
- package/skills/infra/kubernetes-specialist/references/helm-charts.md +912 -912
- package/skills/infra/kubernetes-specialist/references/multi-cluster.md +507 -507
- package/skills/infra/kubernetes-specialist/references/networking.md +447 -447
- package/skills/infra/kubernetes-specialist/references/service-mesh.md +459 -459
- package/skills/infra/kubernetes-specialist/references/storage.md +535 -535
- package/skills/infra/kubernetes-specialist/references/troubleshooting.md +414 -414
- package/skills/infra/kubernetes-specialist/references/workloads.md +377 -377
- package/skills/infra/mcp-developer/SKILL.md +143 -143
- package/skills/infra/mcp-developer/references/protocol.md +244 -244
- package/skills/infra/mcp-developer/references/python-sdk.md +367 -367
- package/skills/infra/mcp-developer/references/resources.md +554 -554
- package/skills/infra/mcp-developer/references/tools.md +480 -480
- package/skills/infra/mcp-developer/references/typescript-sdk.md +350 -350
- package/skills/infra/monitoring-expert/SKILL.md +176 -176
- package/skills/infra/monitoring-expert/references/alerting-rules.md +141 -141
- package/skills/infra/monitoring-expert/references/application-profiling.md +331 -331
- package/skills/infra/monitoring-expert/references/capacity-planning.md +344 -344
- package/skills/infra/monitoring-expert/references/dashboards.md +126 -126
- package/skills/infra/monitoring-expert/references/opentelemetry.md +123 -123
- package/skills/infra/monitoring-expert/references/performance-testing.md +269 -269
- package/skills/infra/monitoring-expert/references/prometheus-metrics.md +136 -136
- package/skills/infra/monitoring-expert/references/structured-logging.md +142 -142
- package/skills/infra/sre-engineer/SKILL.md +181 -181
- package/skills/infra/sre-engineer/references/automation-toil.md +492 -492
- package/skills/infra/sre-engineer/references/error-budget-policy.md +334 -334
- package/skills/infra/sre-engineer/references/incident-chaos.md +576 -576
- package/skills/infra/sre-engineer/references/monitoring-alerting.md +424 -424
- package/skills/infra/sre-engineer/references/slo-sli-management.md +238 -238
- package/skills/infra/terraform-engineer/SKILL.md +143 -143
- package/skills/infra/terraform-engineer/references/best-practices.md +583 -583
- package/skills/infra/terraform-engineer/references/module-patterns.md +297 -297
- package/skills/infra/terraform-engineer/references/providers.md +452 -452
- package/skills/infra/terraform-engineer/references/state-management.md +371 -371
- package/skills/infra/terraform-engineer/references/testing.md +486 -486
- package/skills/infra/websocket-engineer/SKILL.md +168 -168
- package/skills/infra/websocket-engineer/references/alternatives.md +391 -391
- package/skills/infra/websocket-engineer/references/patterns.md +400 -400
- package/skills/infra/websocket-engineer/references/protocol.md +195 -195
- package/skills/infra/websocket-engineer/references/scaling.md +333 -333
- package/skills/infra/websocket-engineer/references/security.md +474 -474
- package/skills/java/java-architect/SKILL.md +132 -132
- package/skills/java/java-architect/references/jpa-optimization.md +393 -393
- package/skills/java/java-architect/references/reactive-webflux.md +356 -356
- package/skills/java/java-architect/references/spring-boot-setup.md +269 -269
- package/skills/java/java-architect/references/spring-security.md +445 -445
- package/skills/java/java-architect/references/testing-patterns.md +500 -500
- package/skills/java/kotlin-specialist/SKILL.md +147 -147
- package/skills/java/kotlin-specialist/references/android-compose.md +419 -419
- package/skills/java/kotlin-specialist/references/coroutines-flow.md +276 -276
- package/skills/java/kotlin-specialist/references/dsl-idioms.md +421 -421
- package/skills/java/kotlin-specialist/references/ktor-server.md +426 -426
- package/skills/java/kotlin-specialist/references/multiplatform-kmp.md +380 -380
- package/skills/java/spring-boot-engineer/SKILL.md +195 -195
- package/skills/java/spring-boot-engineer/references/cloud.md +498 -498
- package/skills/java/spring-boot-engineer/references/data.md +381 -381
- package/skills/java/spring-boot-engineer/references/security.md +459 -459
- package/skills/java/spring-boot-engineer/references/testing.md +545 -545
- package/skills/java/spring-boot-engineer/references/web.md +295 -295
- package/skills/javascript/javascript-pro/SKILL.md +132 -132
- package/skills/javascript/javascript-pro/references/async-patterns.md +334 -334
- package/skills/javascript/javascript-pro/references/browser-apis.md +398 -398
- package/skills/javascript/javascript-pro/references/modern-syntax.md +272 -272
- package/skills/javascript/javascript-pro/references/modules.md +357 -357
- package/skills/javascript/javascript-pro/references/node-essentials.md +471 -471
- package/skills/javascript/nestjs-expert/SKILL.md +206 -206
- package/skills/javascript/nestjs-expert/references/authentication.md +166 -166
- package/skills/javascript/nestjs-expert/references/controllers-routing.md +111 -111
- package/skills/javascript/nestjs-expert/references/dtos-validation.md +153 -153
- package/skills/javascript/nestjs-expert/references/migration-from-express.md +1237 -1237
- package/skills/javascript/nestjs-expert/references/services-di.md +140 -140
- package/skills/javascript/nestjs-expert/references/testing-patterns.md +186 -186
- package/skills/javascript/typescript-pro/SKILL.md +145 -145
- package/skills/javascript/typescript-pro/references/advanced-types.md +259 -259
- package/skills/javascript/typescript-pro/references/configuration.md +445 -445
- package/skills/javascript/typescript-pro/references/patterns.md +484 -484
- package/skills/javascript/typescript-pro/references/type-guards.md +352 -352
- package/skills/javascript/typescript-pro/references/utility-types.md +329 -329
- package/skills/php/laravel-specialist/SKILL.md +262 -262
- package/skills/php/laravel-specialist/references/eloquent.md +351 -351
- package/skills/php/laravel-specialist/references/livewire.md +512 -512
- package/skills/php/laravel-specialist/references/queues.md +423 -423
- package/skills/php/laravel-specialist/references/routing.md +362 -362
- package/skills/php/laravel-specialist/references/testing.md +522 -522
- package/skills/php/php-pro/SKILL.md +206 -206
- package/skills/php/php-pro/references/async-patterns.md +412 -412
- package/skills/php/php-pro/references/laravel-patterns.md +377 -377
- package/skills/php/php-pro/references/modern-php-features.md +323 -323
- package/skills/php/php-pro/references/symfony-patterns.md +466 -466
- package/skills/php/php-pro/references/testing-quality.md +466 -466
- package/skills/product/competitive-analysis/SKILL.md +257 -257
- package/skills/product/meeting-notes/SKILL.md +266 -266
- package/skills/product/prd-template/SKILL.md +150 -150
- package/skills/product/stakeholder-update/SKILL.md +225 -225
- package/skills/product/user-research-synthesis/SKILL.md +235 -235
- package/skills/python/django-expert/SKILL.md +162 -162
- package/skills/python/django-expert/references/authentication.md +145 -145
- package/skills/python/django-expert/references/drf-serializers.md +148 -148
- package/skills/python/django-expert/references/models-orm.md +151 -151
- package/skills/python/django-expert/references/testing-django.md +204 -204
- package/skills/python/django-expert/references/viewsets-views.md +153 -153
- package/skills/python/fastapi-expert/SKILL.md +185 -185
- package/skills/python/fastapi-expert/references/async-sqlalchemy.md +146 -146
- package/skills/python/fastapi-expert/references/authentication.md +159 -159
- package/skills/python/fastapi-expert/references/endpoints-routing.md +142 -142
- package/skills/python/fastapi-expert/references/migration-from-django.md +996 -996
- package/skills/python/fastapi-expert/references/pydantic-v2.md +135 -135
- package/skills/python/fastapi-expert/references/testing-async.md +159 -159
- package/skills/python/pandas-pro/SKILL.md +178 -178
- package/skills/python/pandas-pro/references/aggregation-groupby.md +545 -545
- package/skills/python/pandas-pro/references/data-cleaning.md +500 -500
- package/skills/python/pandas-pro/references/dataframe-operations.md +420 -420
- package/skills/python/pandas-pro/references/merging-joining.md +596 -596
- package/skills/python/pandas-pro/references/performance-optimization.md +597 -597
- package/skills/python/python-pro/SKILL.md +177 -177
- package/skills/python/python-pro/references/async-patterns.md +356 -356
- package/skills/python/python-pro/references/packaging.md +460 -460
- package/skills/python/python-pro/references/standard-library.md +378 -378
- package/skills/python/python-pro/references/testing.md +404 -404
- package/skills/python/python-pro/references/type-system.md +290 -290
- package/skills/quality/chaos-engineer/SKILL.md +182 -182
- package/skills/quality/chaos-engineer/references/chaos-tools.md +511 -511
- package/skills/quality/chaos-engineer/references/experiment-design.md +229 -229
- package/skills/quality/chaos-engineer/references/game-days.md +434 -434
- package/skills/quality/chaos-engineer/references/infrastructure-chaos.md +348 -348
- package/skills/quality/chaos-engineer/references/kubernetes-chaos.md +432 -432
- package/skills/quality/code-reviewer/SKILL.md +119 -119
- package/skills/quality/code-reviewer/references/common-issues.md +142 -142
- package/skills/quality/code-reviewer/references/feedback-examples.md +144 -144
- package/skills/quality/code-reviewer/references/receiving-feedback.md +238 -238
- package/skills/quality/code-reviewer/references/report-template.md +109 -109
- package/skills/quality/code-reviewer/references/review-checklist.md +88 -88
- package/skills/quality/code-reviewer/references/spec-compliance-review.md +258 -258
- package/skills/quality/playwright-expert/SKILL.md +169 -169
- package/skills/quality/playwright-expert/references/api-mocking.md +140 -140
- package/skills/quality/playwright-expert/references/configuration.md +155 -155
- package/skills/quality/playwright-expert/references/debugging-flaky.md +150 -150
- package/skills/quality/playwright-expert/references/page-object-model.md +152 -152
- package/skills/quality/playwright-expert/references/selectors-locators.md +119 -119
- package/skills/quality/secure-code-guardian/SKILL.md +191 -191
- package/skills/quality/secure-code-guardian/references/authentication.md +136 -136
- package/skills/quality/secure-code-guardian/references/input-validation.md +146 -146
- package/skills/quality/secure-code-guardian/references/owasp-prevention.md +135 -135
- package/skills/quality/secure-code-guardian/references/security-headers.md +133 -133
- package/skills/quality/secure-code-guardian/references/xss-csrf.md +157 -157
- package/skills/quality/security-reviewer/SKILL.md +103 -103
- package/skills/quality/security-reviewer/references/infrastructure-security.md +268 -268
- package/skills/quality/security-reviewer/references/penetration-testing.md +268 -268
- package/skills/quality/security-reviewer/references/report-template.md +170 -170
- package/skills/quality/security-reviewer/references/sast-tools.md +117 -117
- package/skills/quality/security-reviewer/references/secret-scanning.md +125 -125
- package/skills/quality/security-reviewer/references/vulnerability-patterns.md +152 -152
- package/skills/quality/senior-qa/README.md +196 -196
- package/skills/quality/senior-qa/SKILL.md +399 -399
- package/skills/quality/senior-qa/references/qa_best_practices.md +964 -964
- package/skills/quality/senior-qa/references/test_automation_patterns.md +1009 -1009
- package/skills/quality/senior-qa/references/testing_strategies.md +649 -649
- package/skills/quality/senior-qa/scripts/coverage_analyzer.py +836 -836
- package/skills/quality/senior-qa/scripts/e2e_test_scaffolder.py +820 -820
- package/skills/quality/senior-qa/scripts/test_suite_generator.py +605 -605
- package/skills/quality/tdd-guide/HOW_TO_USE.md +313 -313
- package/skills/quality/tdd-guide/README.md +680 -680
- package/skills/quality/tdd-guide/SKILL.md +122 -122
- package/skills/quality/tdd-guide/assets/expected_output.json +77 -77
- package/skills/quality/tdd-guide/assets/sample_input_python.json +39 -39
- package/skills/quality/tdd-guide/assets/sample_input_typescript.json +36 -36
- package/skills/quality/tdd-guide/references/ci-integration.md +195 -195
- package/skills/quality/tdd-guide/references/framework-guide.md +206 -206
- package/skills/quality/tdd-guide/references/tdd-best-practices.md +128 -128
- package/skills/quality/tdd-guide/scripts/coverage_analyzer.py +434 -434
- package/skills/quality/tdd-guide/scripts/fixture_generator.py +440 -440
- package/skills/quality/tdd-guide/scripts/format_detector.py +384 -384
- package/skills/quality/tdd-guide/scripts/framework_adapter.py +428 -428
- package/skills/quality/tdd-guide/scripts/metrics_calculator.py +456 -456
- package/skills/quality/tdd-guide/scripts/output_formatter.py +354 -354
- package/skills/quality/tdd-guide/scripts/tdd_workflow.py +474 -474
- package/skills/quality/tdd-guide/scripts/test_generator.py +438 -438
- package/skills/quality/test-master/SKILL.md +94 -94
- package/skills/quality/test-master/references/automation-frameworks.md +294 -294
- package/skills/quality/test-master/references/e2e-testing.md +128 -128
- package/skills/quality/test-master/references/integration-testing.md +120 -120
- package/skills/quality/test-master/references/performance-testing.md +118 -118
- package/skills/quality/test-master/references/qa-methodology.md +247 -247
- package/skills/quality/test-master/references/security-testing.md +127 -127
- package/skills/quality/test-master/references/tdd-iron-laws.md +174 -174
- package/skills/quality/test-master/references/test-reports.md +104 -104
- package/skills/quality/test-master/references/testing-anti-patterns.md +231 -231
- package/skills/quality/test-master/references/unit-testing.md +113 -113
- package/skills/ruby/rails-expert/SKILL.md +154 -154
- package/skills/ruby/rails-expert/references/active-record.md +244 -244
- package/skills/ruby/rails-expert/references/api-development.md +401 -401
- package/skills/ruby/rails-expert/references/background-jobs.md +272 -272
- package/skills/ruby/rails-expert/references/hotwire-turbo.md +228 -228
- package/skills/ruby/rails-expert/references/rspec-testing.md +367 -367
- package/skills/swift/swift-expert/SKILL.md +163 -163
- package/skills/swift/swift-expert/references/async-concurrency.md +360 -360
- package/skills/swift/swift-expert/references/memory-performance.md +377 -377
- package/skills/swift/swift-expert/references/protocol-oriented.md +354 -354
- package/skills/swift/swift-expert/references/swiftui-patterns.md +291 -291
- package/skills/swift/swift-expert/references/testing-patterns.md +399 -399
- package/skills/workflow/brainstorming/SKILL.md +164 -164
- package/skills/workflow/brainstorming/scripts/frame-template.html +214 -214
- package/skills/workflow/brainstorming/scripts/helper.js +88 -88
- package/skills/workflow/brainstorming/scripts/server.cjs +354 -354
- package/skills/workflow/brainstorming/scripts/start-server.sh +148 -148
- package/skills/workflow/brainstorming/scripts/stop-server.sh +56 -56
- package/skills/workflow/brainstorming/spec-document-reviewer-prompt.md +49 -49
- package/skills/workflow/brainstorming/visual-companion.md +287 -287
- package/skills/workflow/documentation/SKILL.md +45 -45
- package/skills/workflow/entropy-management/SKILL.md +115 -115
- package/skills/workflow/executing-plans/SKILL.md +70 -70
- package/skills/workflow/finishing-a-development-branch/SKILL.md +200 -200
- package/skills/workflow/receiving-code-review/SKILL.md +213 -213
- package/skills/workflow/requesting-code-review/SKILL.md +105 -105
- package/skills/workflow/requesting-code-review/code-reviewer.md +146 -146
- package/skills/workflow/requirement-engineering/SKILL.md +111 -111
- package/skills/workflow/systematic-debugging/CREATION-LOG.md +119 -119
- package/skills/workflow/systematic-debugging/SKILL.md +296 -296
- package/skills/workflow/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/skills/workflow/systematic-debugging/condition-based-waiting.md +115 -115
- package/skills/workflow/systematic-debugging/defense-in-depth.md +122 -122
- package/skills/workflow/systematic-debugging/find-polluter.sh +63 -63
- package/skills/workflow/systematic-debugging/root-cause-tracing.md +169 -169
- package/skills/workflow/systematic-debugging/test-academic.md +14 -14
- package/skills/workflow/systematic-debugging/test-pressure-1.md +58 -58
- package/skills/workflow/systematic-debugging/test-pressure-2.md +68 -68
- package/skills/workflow/systematic-debugging/test-pressure-3.md +69 -69
- package/skills/workflow/using-git-worktrees/SKILL.md +218 -218
- package/skills/workflow/verification-before-completion/SKILL.md +139 -139
- package/skills/workflow/writing-plans/SKILL.md +151 -151
- package/skills/workflow/writing-plans/plan-document-reviewer-prompt.md +49 -49
- package/skills/workflow/writing-skills/SKILL.md +655 -655
- package/skills/workflow/writing-skills/anthropic-best-practices.md +1150 -1150
- package/skills/workflow/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/skills/workflow/writing-skills/persuasion-principles.md +187 -187
- package/skills/workflow/writing-skills/render-graphs.js +168 -168
- package/skills/workflow/writing-skills/testing-skills-with-subagents.md +384 -384
|
@@ -1,500 +1,500 @@
|
|
|
1
|
-
# Testing Patterns
|
|
2
|
-
|
|
3
|
-
## Unit Testing with JUnit 5
|
|
4
|
-
|
|
5
|
-
```java
|
|
6
|
-
package com.example.application.service;
|
|
7
|
-
|
|
8
|
-
import com.example.application.dto.UserRequest;
|
|
9
|
-
import com.example.application.dto.UserResponse;
|
|
10
|
-
import com.example.application.mapper.UserMapper;
|
|
11
|
-
import com.example.domain.model.User;
|
|
12
|
-
import com.example.domain.repository.UserRepository;
|
|
13
|
-
import org.junit.jupiter.api.BeforeEach;
|
|
14
|
-
import org.junit.jupiter.api.DisplayName;
|
|
15
|
-
import org.junit.jupiter.api.Test;
|
|
16
|
-
import org.junit.jupiter.api.extension.ExtendWith;
|
|
17
|
-
import org.junit.jupiter.params.ParameterizedTest;
|
|
18
|
-
import org.junit.jupiter.params.provider.ValueSource;
|
|
19
|
-
import org.mockito.InjectMocks;
|
|
20
|
-
import org.mockito.Mock;
|
|
21
|
-
import org.mockito.junit.jupiter.MockitoExtension;
|
|
22
|
-
|
|
23
|
-
import java.util.Optional;
|
|
24
|
-
|
|
25
|
-
import static org.assertj.core.api.Assertions.*;
|
|
26
|
-
import static org.mockito.ArgumentMatchers.*;
|
|
27
|
-
import static org.mockito.Mockito.*;
|
|
28
|
-
|
|
29
|
-
@ExtendWith(MockitoExtension.class)
|
|
30
|
-
@DisplayName("User Service Tests")
|
|
31
|
-
class UserServiceTest {
|
|
32
|
-
|
|
33
|
-
@Mock
|
|
34
|
-
private UserRepository userRepository;
|
|
35
|
-
|
|
36
|
-
@Mock
|
|
37
|
-
private UserMapper userMapper;
|
|
38
|
-
|
|
39
|
-
@InjectMocks
|
|
40
|
-
private UserService userService;
|
|
41
|
-
|
|
42
|
-
private User testUser;
|
|
43
|
-
private UserRequest userRequest;
|
|
44
|
-
private UserResponse userResponse;
|
|
45
|
-
|
|
46
|
-
@BeforeEach
|
|
47
|
-
void setUp() {
|
|
48
|
-
testUser = User.builder()
|
|
49
|
-
.id(1L)
|
|
50
|
-
.email("test@example.com")
|
|
51
|
-
.username("testuser")
|
|
52
|
-
.active(true)
|
|
53
|
-
.build();
|
|
54
|
-
|
|
55
|
-
userRequest = new UserRequest("test@example.com", "testuser");
|
|
56
|
-
userResponse = new UserResponse(1L, "test@example.com", "testuser");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@Test
|
|
60
|
-
@DisplayName("Should find user by ID successfully")
|
|
61
|
-
void shouldFindUserById() {
|
|
62
|
-
// Given
|
|
63
|
-
when(userRepository.findById(1L)).thenReturn(Optional.of(testUser));
|
|
64
|
-
when(userMapper.toResponse(testUser)).thenReturn(userResponse);
|
|
65
|
-
|
|
66
|
-
// When
|
|
67
|
-
UserResponse result = userService.findById(1L);
|
|
68
|
-
|
|
69
|
-
// Then
|
|
70
|
-
assertThat(result).isNotNull();
|
|
71
|
-
assertThat(result.email()).isEqualTo("test@example.com");
|
|
72
|
-
verify(userRepository).findById(1L);
|
|
73
|
-
verify(userMapper).toResponse(testUser);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@Test
|
|
77
|
-
@DisplayName("Should throw exception when user not found")
|
|
78
|
-
void shouldThrowWhenUserNotFound() {
|
|
79
|
-
// Given
|
|
80
|
-
when(userRepository.findById(anyLong())).thenReturn(Optional.empty());
|
|
81
|
-
|
|
82
|
-
// When / Then
|
|
83
|
-
assertThatThrownBy(() -> userService.findById(999L))
|
|
84
|
-
.isInstanceOf(EntityNotFoundException.class)
|
|
85
|
-
.hasMessageContaining("User not found");
|
|
86
|
-
|
|
87
|
-
verify(userRepository).findById(999L);
|
|
88
|
-
verifyNoInteractions(userMapper);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
@Test
|
|
92
|
-
@DisplayName("Should create user successfully")
|
|
93
|
-
void shouldCreateUser() {
|
|
94
|
-
// Given
|
|
95
|
-
when(userMapper.toEntity(userRequest)).thenReturn(testUser);
|
|
96
|
-
when(userRepository.save(any(User.class))).thenReturn(testUser);
|
|
97
|
-
when(userMapper.toResponse(testUser)).thenReturn(userResponse);
|
|
98
|
-
|
|
99
|
-
// When
|
|
100
|
-
UserResponse result = userService.create(userRequest);
|
|
101
|
-
|
|
102
|
-
// Then
|
|
103
|
-
assertThat(result).isNotNull();
|
|
104
|
-
assertThat(result.id()).isEqualTo(1L);
|
|
105
|
-
verify(userRepository).save(any(User.class));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@ParameterizedTest
|
|
109
|
-
@ValueSource(strings = {"admin", "user", "moderator"})
|
|
110
|
-
@DisplayName("Should validate different user roles")
|
|
111
|
-
void shouldValidateUserRoles(String role) {
|
|
112
|
-
// Test with multiple roles
|
|
113
|
-
assertThat(role).isNotBlank();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## Integration Testing with TestContainers
|
|
119
|
-
|
|
120
|
-
```java
|
|
121
|
-
package com.example.integration;
|
|
122
|
-
|
|
123
|
-
import com.example.application.dto.UserRequest;
|
|
124
|
-
import com.example.application.dto.UserResponse;
|
|
125
|
-
import org.junit.jupiter.api.BeforeEach;
|
|
126
|
-
import org.junit.jupiter.api.Test;
|
|
127
|
-
import org.springframework.beans.factory.annotation.Autowired;
|
|
128
|
-
import org.springframework.boot.test.context.SpringBootTest;
|
|
129
|
-
import org.springframework.boot.test.web.client.TestRestTemplate;
|
|
130
|
-
import org.springframework.http.HttpStatus;
|
|
131
|
-
import org.springframework.http.ResponseEntity;
|
|
132
|
-
import org.springframework.test.context.DynamicPropertyRegistry;
|
|
133
|
-
import org.springframework.test.context.DynamicPropertySource;
|
|
134
|
-
import org.testcontainers.containers.PostgreSQLContainer;
|
|
135
|
-
import org.testcontainers.junit.jupiter.Container;
|
|
136
|
-
import org.testcontainers.junit.jupiter.Testcontainers;
|
|
137
|
-
|
|
138
|
-
import static org.assertj.core.api.Assertions.assertThat;
|
|
139
|
-
|
|
140
|
-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
141
|
-
@Testcontainers
|
|
142
|
-
class UserIntegrationTest {
|
|
143
|
-
|
|
144
|
-
@Container
|
|
145
|
-
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
|
|
146
|
-
.withDatabaseName("testdb")
|
|
147
|
-
.withUsername("test")
|
|
148
|
-
.withPassword("test");
|
|
149
|
-
|
|
150
|
-
@DynamicPropertySource
|
|
151
|
-
static void configureProperties(DynamicPropertyRegistry registry) {
|
|
152
|
-
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
153
|
-
registry.add("spring.datasource.username", postgres::getUsername);
|
|
154
|
-
registry.add("spring.datasource.password", postgres::getPassword);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@Autowired
|
|
158
|
-
private TestRestTemplate restTemplate;
|
|
159
|
-
|
|
160
|
-
@BeforeEach
|
|
161
|
-
void setUp() {
|
|
162
|
-
// Clean up database before each test
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
@Test
|
|
166
|
-
void shouldCreateAndRetrieveUser() {
|
|
167
|
-
// Create user
|
|
168
|
-
UserRequest request = new UserRequest("test@example.com", "testuser");
|
|
169
|
-
ResponseEntity<UserResponse> createResponse = restTemplate.postForEntity(
|
|
170
|
-
"/api/users",
|
|
171
|
-
request,
|
|
172
|
-
UserResponse.class
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED);
|
|
176
|
-
assertThat(createResponse.getBody()).isNotNull();
|
|
177
|
-
Long userId = createResponse.getBody().id();
|
|
178
|
-
|
|
179
|
-
// Retrieve user
|
|
180
|
-
ResponseEntity<UserResponse> getResponse = restTemplate.getForEntity(
|
|
181
|
-
"/api/users/" + userId,
|
|
182
|
-
UserResponse.class
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
|
|
186
|
-
assertThat(getResponse.getBody().email()).isEqualTo("test@example.com");
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Repository Testing
|
|
192
|
-
|
|
193
|
-
```java
|
|
194
|
-
package com.example.domain.repository;
|
|
195
|
-
|
|
196
|
-
import com.example.domain.model.User;
|
|
197
|
-
import org.junit.jupiter.api.Test;
|
|
198
|
-
import org.springframework.beans.factory.annotation.Autowired;
|
|
199
|
-
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
200
|
-
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
201
|
-
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
|
|
202
|
-
import org.testcontainers.containers.PostgreSQLContainer;
|
|
203
|
-
import org.testcontainers.junit.jupiter.Container;
|
|
204
|
-
import org.testcontainers.junit.jupiter.Testcontainers;
|
|
205
|
-
|
|
206
|
-
import java.util.Optional;
|
|
207
|
-
|
|
208
|
-
import static org.assertj.core.api.Assertions.assertThat;
|
|
209
|
-
|
|
210
|
-
@DataJpaTest
|
|
211
|
-
@Testcontainers
|
|
212
|
-
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
213
|
-
class UserRepositoryTest {
|
|
214
|
-
|
|
215
|
-
@Container
|
|
216
|
-
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
|
|
217
|
-
|
|
218
|
-
@Autowired
|
|
219
|
-
private TestEntityManager entityManager;
|
|
220
|
-
|
|
221
|
-
@Autowired
|
|
222
|
-
private UserRepository userRepository;
|
|
223
|
-
|
|
224
|
-
@Test
|
|
225
|
-
void shouldFindUserByEmail() {
|
|
226
|
-
// Given
|
|
227
|
-
User user = User.builder()
|
|
228
|
-
.email("test@example.com")
|
|
229
|
-
.username("testuser")
|
|
230
|
-
.active(true)
|
|
231
|
-
.build();
|
|
232
|
-
entityManager.persistAndFlush(user);
|
|
233
|
-
|
|
234
|
-
// When
|
|
235
|
-
Optional<User> found = userRepository.findByEmail("test@example.com");
|
|
236
|
-
|
|
237
|
-
// Then
|
|
238
|
-
assertThat(found).isPresent();
|
|
239
|
-
assertThat(found.get().getEmail()).isEqualTo("test@example.com");
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
@Test
|
|
243
|
-
void shouldCountActiveUsers() {
|
|
244
|
-
// Given
|
|
245
|
-
User activeUser = User.builder()
|
|
246
|
-
.email("active@example.com")
|
|
247
|
-
.username("active")
|
|
248
|
-
.active(true)
|
|
249
|
-
.build();
|
|
250
|
-
User inactiveUser = User.builder()
|
|
251
|
-
.email("inactive@example.com")
|
|
252
|
-
.username("inactive")
|
|
253
|
-
.active(false)
|
|
254
|
-
.build();
|
|
255
|
-
entityManager.persist(activeUser);
|
|
256
|
-
entityManager.persist(inactiveUser);
|
|
257
|
-
entityManager.flush();
|
|
258
|
-
|
|
259
|
-
// When
|
|
260
|
-
long count = userRepository.countByActiveTrue();
|
|
261
|
-
|
|
262
|
-
// Then
|
|
263
|
-
assertThat(count).isEqualTo(1);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## REST Controller Testing
|
|
269
|
-
|
|
270
|
-
```java
|
|
271
|
-
package com.example.presentation.rest;
|
|
272
|
-
|
|
273
|
-
import com.example.application.dto.UserRequest;
|
|
274
|
-
import com.example.application.dto.UserResponse;
|
|
275
|
-
import com.example.application.service.UserService;
|
|
276
|
-
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
277
|
-
import org.junit.jupiter.api.Test;
|
|
278
|
-
import org.springframework.beans.factory.annotation.Autowired;
|
|
279
|
-
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
|
280
|
-
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
281
|
-
import org.springframework.http.MediaType;
|
|
282
|
-
import org.springframework.security.test.context.support.WithMockUser;
|
|
283
|
-
import org.springframework.test.web.servlet.MockMvc;
|
|
284
|
-
|
|
285
|
-
import static org.mockito.ArgumentMatchers.any;
|
|
286
|
-
import static org.mockito.Mockito.when;
|
|
287
|
-
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
|
288
|
-
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
|
289
|
-
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|
290
|
-
|
|
291
|
-
@WebMvcTest(UserController.class)
|
|
292
|
-
class UserControllerTest {
|
|
293
|
-
|
|
294
|
-
@Autowired
|
|
295
|
-
private MockMvc mockMvc;
|
|
296
|
-
|
|
297
|
-
@Autowired
|
|
298
|
-
private ObjectMapper objectMapper;
|
|
299
|
-
|
|
300
|
-
@MockBean
|
|
301
|
-
private UserService userService;
|
|
302
|
-
|
|
303
|
-
@Test
|
|
304
|
-
@WithMockUser
|
|
305
|
-
void shouldGetUserById() throws Exception {
|
|
306
|
-
// Given
|
|
307
|
-
UserResponse response = new UserResponse(1L, "test@example.com", "testuser");
|
|
308
|
-
when(userService.findById(1L)).thenReturn(response);
|
|
309
|
-
|
|
310
|
-
// When / Then
|
|
311
|
-
mockMvc.perform(get("/api/users/1"))
|
|
312
|
-
.andExpect(status().isOk())
|
|
313
|
-
.andExpect(jsonPath("$.id").value(1))
|
|
314
|
-
.andExpect(jsonPath("$.email").value("test@example.com"));
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
@Test
|
|
318
|
-
@WithMockUser
|
|
319
|
-
void shouldCreateUser() throws Exception {
|
|
320
|
-
// Given
|
|
321
|
-
UserRequest request = new UserRequest("test@example.com", "testuser");
|
|
322
|
-
UserResponse response = new UserResponse(1L, "test@example.com", "testuser");
|
|
323
|
-
when(userService.create(any(UserRequest.class))).thenReturn(response);
|
|
324
|
-
|
|
325
|
-
// When / Then
|
|
326
|
-
mockMvc.perform(post("/api/users")
|
|
327
|
-
.with(csrf())
|
|
328
|
-
.contentType(MediaType.APPLICATION_JSON)
|
|
329
|
-
.content(objectMapper.writeValueAsString(request)))
|
|
330
|
-
.andExpect(status().isCreated())
|
|
331
|
-
.andExpect(jsonPath("$.id").value(1));
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
@Test
|
|
335
|
-
void shouldReturn401WhenNotAuthenticated() throws Exception {
|
|
336
|
-
mockMvc.perform(get("/api/users/1"))
|
|
337
|
-
.andExpect(status().isUnauthorized());
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
## Test Configuration
|
|
343
|
-
|
|
344
|
-
```java
|
|
345
|
-
package com.example.config;
|
|
346
|
-
|
|
347
|
-
import org.springframework.boot.test.context.TestConfiguration;
|
|
348
|
-
import org.springframework.context.annotation.Bean;
|
|
349
|
-
import org.springframework.context.annotation.Primary;
|
|
350
|
-
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
|
351
|
-
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
352
|
-
|
|
353
|
-
@TestConfiguration
|
|
354
|
-
public class TestSecurityConfig {
|
|
355
|
-
|
|
356
|
-
@Bean
|
|
357
|
-
@Primary
|
|
358
|
-
public PasswordEncoder passwordEncoder() {
|
|
359
|
-
return NoOpPasswordEncoder.getInstance();
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
## Test Data Builders
|
|
365
|
-
|
|
366
|
-
```java
|
|
367
|
-
package com.example.test.builders;
|
|
368
|
-
|
|
369
|
-
import com.example.domain.model.User;
|
|
370
|
-
|
|
371
|
-
public class UserTestBuilder {
|
|
372
|
-
|
|
373
|
-
private Long id = 1L;
|
|
374
|
-
private String email = "test@example.com";
|
|
375
|
-
private String username = "testuser";
|
|
376
|
-
private Boolean active = true;
|
|
377
|
-
|
|
378
|
-
public static UserTestBuilder aUser() {
|
|
379
|
-
return new UserTestBuilder();
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
public UserTestBuilder withId(Long id) {
|
|
383
|
-
this.id = id;
|
|
384
|
-
return this;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
public UserTestBuilder withEmail(String email) {
|
|
388
|
-
this.email = email;
|
|
389
|
-
return this;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
public UserTestBuilder inactive() {
|
|
393
|
-
this.active = false;
|
|
394
|
-
return this;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
public User build() {
|
|
398
|
-
return User.builder()
|
|
399
|
-
.id(id)
|
|
400
|
-
.email(email)
|
|
401
|
-
.username(username)
|
|
402
|
-
.active(active)
|
|
403
|
-
.build();
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Usage
|
|
408
|
-
User user = aUser()
|
|
409
|
-
.withEmail("custom@example.com")
|
|
410
|
-
.inactive()
|
|
411
|
-
.build();
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
## Performance Testing with JMH
|
|
415
|
-
|
|
416
|
-
```java
|
|
417
|
-
package com.example.benchmark;
|
|
418
|
-
|
|
419
|
-
import org.openjdk.jmh.annotations.*;
|
|
420
|
-
import org.openjdk.jmh.runner.Runner;
|
|
421
|
-
import org.openjdk.jmh.runner.options.Options;
|
|
422
|
-
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
|
423
|
-
|
|
424
|
-
import java.util.concurrent.TimeUnit;
|
|
425
|
-
|
|
426
|
-
@BenchmarkMode(Mode.AverageTime)
|
|
427
|
-
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
428
|
-
@State(Scope.Benchmark)
|
|
429
|
-
@Fork(value = 2, warmups = 1)
|
|
430
|
-
@Warmup(iterations = 3)
|
|
431
|
-
@Measurement(iterations = 5)
|
|
432
|
-
public class UserServiceBenchmark {
|
|
433
|
-
|
|
434
|
-
private UserService userService;
|
|
435
|
-
|
|
436
|
-
@Setup
|
|
437
|
-
public void setup() {
|
|
438
|
-
// Initialize test data
|
|
439
|
-
userService = new UserService();
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
@Benchmark
|
|
443
|
-
public void benchmarkFindUser() {
|
|
444
|
-
userService.findById(1L);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
public static void main(String[] args) throws Exception {
|
|
448
|
-
Options opt = new OptionsBuilder()
|
|
449
|
-
.include(UserServiceBenchmark.class.getSimpleName())
|
|
450
|
-
.build();
|
|
451
|
-
new Runner(opt).run();
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
## Test Containers Shared Instance
|
|
457
|
-
|
|
458
|
-
```java
|
|
459
|
-
package com.example.test;
|
|
460
|
-
|
|
461
|
-
import org.springframework.test.context.DynamicPropertyRegistry;
|
|
462
|
-
import org.springframework.test.context.DynamicPropertySource;
|
|
463
|
-
import org.testcontainers.containers.PostgreSQLContainer;
|
|
464
|
-
|
|
465
|
-
public abstract class AbstractIntegrationTest {
|
|
466
|
-
|
|
467
|
-
static final PostgreSQLContainer<?> postgres;
|
|
468
|
-
|
|
469
|
-
static {
|
|
470
|
-
postgres = new PostgreSQLContainer<>("postgres:16-alpine")
|
|
471
|
-
.withReuse(true);
|
|
472
|
-
postgres.start();
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
@DynamicPropertySource
|
|
476
|
-
static void configureProperties(DynamicPropertyRegistry registry) {
|
|
477
|
-
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
478
|
-
registry.add("spring.datasource.username", postgres::getUsername);
|
|
479
|
-
registry.add("spring.datasource.password", postgres::getPassword);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
## Quick Reference
|
|
485
|
-
|
|
486
|
-
| Annotation | Purpose |
|
|
487
|
-
|-----------|---------|
|
|
488
|
-
| `@Test` | Mark test method |
|
|
489
|
-
| `@BeforeEach` | Run before each test |
|
|
490
|
-
| `@AfterEach` | Run after each test |
|
|
491
|
-
| `@DisplayName` | Readable test name |
|
|
492
|
-
| `@ParameterizedTest` | Data-driven tests |
|
|
493
|
-
| `@ExtendWith` | Register extensions |
|
|
494
|
-
| `@SpringBootTest` | Full application context |
|
|
495
|
-
| `@WebMvcTest` | Test MVC layer only |
|
|
496
|
-
| `@DataJpaTest` | Test repository layer |
|
|
497
|
-
| `@MockBean` | Mock Spring bean |
|
|
498
|
-
| `@WithMockUser` | Mock authenticated user |
|
|
499
|
-
| `assertThat()` | AssertJ fluent assertions |
|
|
500
|
-
| `verify()` | Mockito verification |
|
|
1
|
+
# Testing Patterns
|
|
2
|
+
|
|
3
|
+
## Unit Testing with JUnit 5
|
|
4
|
+
|
|
5
|
+
```java
|
|
6
|
+
package com.example.application.service;
|
|
7
|
+
|
|
8
|
+
import com.example.application.dto.UserRequest;
|
|
9
|
+
import com.example.application.dto.UserResponse;
|
|
10
|
+
import com.example.application.mapper.UserMapper;
|
|
11
|
+
import com.example.domain.model.User;
|
|
12
|
+
import com.example.domain.repository.UserRepository;
|
|
13
|
+
import org.junit.jupiter.api.BeforeEach;
|
|
14
|
+
import org.junit.jupiter.api.DisplayName;
|
|
15
|
+
import org.junit.jupiter.api.Test;
|
|
16
|
+
import org.junit.jupiter.api.extension.ExtendWith;
|
|
17
|
+
import org.junit.jupiter.params.ParameterizedTest;
|
|
18
|
+
import org.junit.jupiter.params.provider.ValueSource;
|
|
19
|
+
import org.mockito.InjectMocks;
|
|
20
|
+
import org.mockito.Mock;
|
|
21
|
+
import org.mockito.junit.jupiter.MockitoExtension;
|
|
22
|
+
|
|
23
|
+
import java.util.Optional;
|
|
24
|
+
|
|
25
|
+
import static org.assertj.core.api.Assertions.*;
|
|
26
|
+
import static org.mockito.ArgumentMatchers.*;
|
|
27
|
+
import static org.mockito.Mockito.*;
|
|
28
|
+
|
|
29
|
+
@ExtendWith(MockitoExtension.class)
|
|
30
|
+
@DisplayName("User Service Tests")
|
|
31
|
+
class UserServiceTest {
|
|
32
|
+
|
|
33
|
+
@Mock
|
|
34
|
+
private UserRepository userRepository;
|
|
35
|
+
|
|
36
|
+
@Mock
|
|
37
|
+
private UserMapper userMapper;
|
|
38
|
+
|
|
39
|
+
@InjectMocks
|
|
40
|
+
private UserService userService;
|
|
41
|
+
|
|
42
|
+
private User testUser;
|
|
43
|
+
private UserRequest userRequest;
|
|
44
|
+
private UserResponse userResponse;
|
|
45
|
+
|
|
46
|
+
@BeforeEach
|
|
47
|
+
void setUp() {
|
|
48
|
+
testUser = User.builder()
|
|
49
|
+
.id(1L)
|
|
50
|
+
.email("test@example.com")
|
|
51
|
+
.username("testuser")
|
|
52
|
+
.active(true)
|
|
53
|
+
.build();
|
|
54
|
+
|
|
55
|
+
userRequest = new UserRequest("test@example.com", "testuser");
|
|
56
|
+
userResponse = new UserResponse(1L, "test@example.com", "testuser");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Test
|
|
60
|
+
@DisplayName("Should find user by ID successfully")
|
|
61
|
+
void shouldFindUserById() {
|
|
62
|
+
// Given
|
|
63
|
+
when(userRepository.findById(1L)).thenReturn(Optional.of(testUser));
|
|
64
|
+
when(userMapper.toResponse(testUser)).thenReturn(userResponse);
|
|
65
|
+
|
|
66
|
+
// When
|
|
67
|
+
UserResponse result = userService.findById(1L);
|
|
68
|
+
|
|
69
|
+
// Then
|
|
70
|
+
assertThat(result).isNotNull();
|
|
71
|
+
assertThat(result.email()).isEqualTo("test@example.com");
|
|
72
|
+
verify(userRepository).findById(1L);
|
|
73
|
+
verify(userMapper).toResponse(testUser);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@Test
|
|
77
|
+
@DisplayName("Should throw exception when user not found")
|
|
78
|
+
void shouldThrowWhenUserNotFound() {
|
|
79
|
+
// Given
|
|
80
|
+
when(userRepository.findById(anyLong())).thenReturn(Optional.empty());
|
|
81
|
+
|
|
82
|
+
// When / Then
|
|
83
|
+
assertThatThrownBy(() -> userService.findById(999L))
|
|
84
|
+
.isInstanceOf(EntityNotFoundException.class)
|
|
85
|
+
.hasMessageContaining("User not found");
|
|
86
|
+
|
|
87
|
+
verify(userRepository).findById(999L);
|
|
88
|
+
verifyNoInteractions(userMapper);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@Test
|
|
92
|
+
@DisplayName("Should create user successfully")
|
|
93
|
+
void shouldCreateUser() {
|
|
94
|
+
// Given
|
|
95
|
+
when(userMapper.toEntity(userRequest)).thenReturn(testUser);
|
|
96
|
+
when(userRepository.save(any(User.class))).thenReturn(testUser);
|
|
97
|
+
when(userMapper.toResponse(testUser)).thenReturn(userResponse);
|
|
98
|
+
|
|
99
|
+
// When
|
|
100
|
+
UserResponse result = userService.create(userRequest);
|
|
101
|
+
|
|
102
|
+
// Then
|
|
103
|
+
assertThat(result).isNotNull();
|
|
104
|
+
assertThat(result.id()).isEqualTo(1L);
|
|
105
|
+
verify(userRepository).save(any(User.class));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@ParameterizedTest
|
|
109
|
+
@ValueSource(strings = {"admin", "user", "moderator"})
|
|
110
|
+
@DisplayName("Should validate different user roles")
|
|
111
|
+
void shouldValidateUserRoles(String role) {
|
|
112
|
+
// Test with multiple roles
|
|
113
|
+
assertThat(role).isNotBlank();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Integration Testing with TestContainers
|
|
119
|
+
|
|
120
|
+
```java
|
|
121
|
+
package com.example.integration;
|
|
122
|
+
|
|
123
|
+
import com.example.application.dto.UserRequest;
|
|
124
|
+
import com.example.application.dto.UserResponse;
|
|
125
|
+
import org.junit.jupiter.api.BeforeEach;
|
|
126
|
+
import org.junit.jupiter.api.Test;
|
|
127
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
128
|
+
import org.springframework.boot.test.context.SpringBootTest;
|
|
129
|
+
import org.springframework.boot.test.web.client.TestRestTemplate;
|
|
130
|
+
import org.springframework.http.HttpStatus;
|
|
131
|
+
import org.springframework.http.ResponseEntity;
|
|
132
|
+
import org.springframework.test.context.DynamicPropertyRegistry;
|
|
133
|
+
import org.springframework.test.context.DynamicPropertySource;
|
|
134
|
+
import org.testcontainers.containers.PostgreSQLContainer;
|
|
135
|
+
import org.testcontainers.junit.jupiter.Container;
|
|
136
|
+
import org.testcontainers.junit.jupiter.Testcontainers;
|
|
137
|
+
|
|
138
|
+
import static org.assertj.core.api.Assertions.assertThat;
|
|
139
|
+
|
|
140
|
+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
141
|
+
@Testcontainers
|
|
142
|
+
class UserIntegrationTest {
|
|
143
|
+
|
|
144
|
+
@Container
|
|
145
|
+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
|
|
146
|
+
.withDatabaseName("testdb")
|
|
147
|
+
.withUsername("test")
|
|
148
|
+
.withPassword("test");
|
|
149
|
+
|
|
150
|
+
@DynamicPropertySource
|
|
151
|
+
static void configureProperties(DynamicPropertyRegistry registry) {
|
|
152
|
+
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
153
|
+
registry.add("spring.datasource.username", postgres::getUsername);
|
|
154
|
+
registry.add("spring.datasource.password", postgres::getPassword);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@Autowired
|
|
158
|
+
private TestRestTemplate restTemplate;
|
|
159
|
+
|
|
160
|
+
@BeforeEach
|
|
161
|
+
void setUp() {
|
|
162
|
+
// Clean up database before each test
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@Test
|
|
166
|
+
void shouldCreateAndRetrieveUser() {
|
|
167
|
+
// Create user
|
|
168
|
+
UserRequest request = new UserRequest("test@example.com", "testuser");
|
|
169
|
+
ResponseEntity<UserResponse> createResponse = restTemplate.postForEntity(
|
|
170
|
+
"/api/users",
|
|
171
|
+
request,
|
|
172
|
+
UserResponse.class
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED);
|
|
176
|
+
assertThat(createResponse.getBody()).isNotNull();
|
|
177
|
+
Long userId = createResponse.getBody().id();
|
|
178
|
+
|
|
179
|
+
// Retrieve user
|
|
180
|
+
ResponseEntity<UserResponse> getResponse = restTemplate.getForEntity(
|
|
181
|
+
"/api/users/" + userId,
|
|
182
|
+
UserResponse.class
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
|
|
186
|
+
assertThat(getResponse.getBody().email()).isEqualTo("test@example.com");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Repository Testing
|
|
192
|
+
|
|
193
|
+
```java
|
|
194
|
+
package com.example.domain.repository;
|
|
195
|
+
|
|
196
|
+
import com.example.domain.model.User;
|
|
197
|
+
import org.junit.jupiter.api.Test;
|
|
198
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
199
|
+
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
200
|
+
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
201
|
+
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
|
|
202
|
+
import org.testcontainers.containers.PostgreSQLContainer;
|
|
203
|
+
import org.testcontainers.junit.jupiter.Container;
|
|
204
|
+
import org.testcontainers.junit.jupiter.Testcontainers;
|
|
205
|
+
|
|
206
|
+
import java.util.Optional;
|
|
207
|
+
|
|
208
|
+
import static org.assertj.core.api.Assertions.assertThat;
|
|
209
|
+
|
|
210
|
+
@DataJpaTest
|
|
211
|
+
@Testcontainers
|
|
212
|
+
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
213
|
+
class UserRepositoryTest {
|
|
214
|
+
|
|
215
|
+
@Container
|
|
216
|
+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
|
|
217
|
+
|
|
218
|
+
@Autowired
|
|
219
|
+
private TestEntityManager entityManager;
|
|
220
|
+
|
|
221
|
+
@Autowired
|
|
222
|
+
private UserRepository userRepository;
|
|
223
|
+
|
|
224
|
+
@Test
|
|
225
|
+
void shouldFindUserByEmail() {
|
|
226
|
+
// Given
|
|
227
|
+
User user = User.builder()
|
|
228
|
+
.email("test@example.com")
|
|
229
|
+
.username("testuser")
|
|
230
|
+
.active(true)
|
|
231
|
+
.build();
|
|
232
|
+
entityManager.persistAndFlush(user);
|
|
233
|
+
|
|
234
|
+
// When
|
|
235
|
+
Optional<User> found = userRepository.findByEmail("test@example.com");
|
|
236
|
+
|
|
237
|
+
// Then
|
|
238
|
+
assertThat(found).isPresent();
|
|
239
|
+
assertThat(found.get().getEmail()).isEqualTo("test@example.com");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@Test
|
|
243
|
+
void shouldCountActiveUsers() {
|
|
244
|
+
// Given
|
|
245
|
+
User activeUser = User.builder()
|
|
246
|
+
.email("active@example.com")
|
|
247
|
+
.username("active")
|
|
248
|
+
.active(true)
|
|
249
|
+
.build();
|
|
250
|
+
User inactiveUser = User.builder()
|
|
251
|
+
.email("inactive@example.com")
|
|
252
|
+
.username("inactive")
|
|
253
|
+
.active(false)
|
|
254
|
+
.build();
|
|
255
|
+
entityManager.persist(activeUser);
|
|
256
|
+
entityManager.persist(inactiveUser);
|
|
257
|
+
entityManager.flush();
|
|
258
|
+
|
|
259
|
+
// When
|
|
260
|
+
long count = userRepository.countByActiveTrue();
|
|
261
|
+
|
|
262
|
+
// Then
|
|
263
|
+
assertThat(count).isEqualTo(1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## REST Controller Testing
|
|
269
|
+
|
|
270
|
+
```java
|
|
271
|
+
package com.example.presentation.rest;
|
|
272
|
+
|
|
273
|
+
import com.example.application.dto.UserRequest;
|
|
274
|
+
import com.example.application.dto.UserResponse;
|
|
275
|
+
import com.example.application.service.UserService;
|
|
276
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
277
|
+
import org.junit.jupiter.api.Test;
|
|
278
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
279
|
+
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
|
280
|
+
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
281
|
+
import org.springframework.http.MediaType;
|
|
282
|
+
import org.springframework.security.test.context.support.WithMockUser;
|
|
283
|
+
import org.springframework.test.web.servlet.MockMvc;
|
|
284
|
+
|
|
285
|
+
import static org.mockito.ArgumentMatchers.any;
|
|
286
|
+
import static org.mockito.Mockito.when;
|
|
287
|
+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
|
288
|
+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
|
289
|
+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|
290
|
+
|
|
291
|
+
@WebMvcTest(UserController.class)
|
|
292
|
+
class UserControllerTest {
|
|
293
|
+
|
|
294
|
+
@Autowired
|
|
295
|
+
private MockMvc mockMvc;
|
|
296
|
+
|
|
297
|
+
@Autowired
|
|
298
|
+
private ObjectMapper objectMapper;
|
|
299
|
+
|
|
300
|
+
@MockBean
|
|
301
|
+
private UserService userService;
|
|
302
|
+
|
|
303
|
+
@Test
|
|
304
|
+
@WithMockUser
|
|
305
|
+
void shouldGetUserById() throws Exception {
|
|
306
|
+
// Given
|
|
307
|
+
UserResponse response = new UserResponse(1L, "test@example.com", "testuser");
|
|
308
|
+
when(userService.findById(1L)).thenReturn(response);
|
|
309
|
+
|
|
310
|
+
// When / Then
|
|
311
|
+
mockMvc.perform(get("/api/users/1"))
|
|
312
|
+
.andExpect(status().isOk())
|
|
313
|
+
.andExpect(jsonPath("$.id").value(1))
|
|
314
|
+
.andExpect(jsonPath("$.email").value("test@example.com"));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
@Test
|
|
318
|
+
@WithMockUser
|
|
319
|
+
void shouldCreateUser() throws Exception {
|
|
320
|
+
// Given
|
|
321
|
+
UserRequest request = new UserRequest("test@example.com", "testuser");
|
|
322
|
+
UserResponse response = new UserResponse(1L, "test@example.com", "testuser");
|
|
323
|
+
when(userService.create(any(UserRequest.class))).thenReturn(response);
|
|
324
|
+
|
|
325
|
+
// When / Then
|
|
326
|
+
mockMvc.perform(post("/api/users")
|
|
327
|
+
.with(csrf())
|
|
328
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
329
|
+
.content(objectMapper.writeValueAsString(request)))
|
|
330
|
+
.andExpect(status().isCreated())
|
|
331
|
+
.andExpect(jsonPath("$.id").value(1));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
@Test
|
|
335
|
+
void shouldReturn401WhenNotAuthenticated() throws Exception {
|
|
336
|
+
mockMvc.perform(get("/api/users/1"))
|
|
337
|
+
.andExpect(status().isUnauthorized());
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Test Configuration
|
|
343
|
+
|
|
344
|
+
```java
|
|
345
|
+
package com.example.config;
|
|
346
|
+
|
|
347
|
+
import org.springframework.boot.test.context.TestConfiguration;
|
|
348
|
+
import org.springframework.context.annotation.Bean;
|
|
349
|
+
import org.springframework.context.annotation.Primary;
|
|
350
|
+
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
|
351
|
+
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
352
|
+
|
|
353
|
+
@TestConfiguration
|
|
354
|
+
public class TestSecurityConfig {
|
|
355
|
+
|
|
356
|
+
@Bean
|
|
357
|
+
@Primary
|
|
358
|
+
public PasswordEncoder passwordEncoder() {
|
|
359
|
+
return NoOpPasswordEncoder.getInstance();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Test Data Builders
|
|
365
|
+
|
|
366
|
+
```java
|
|
367
|
+
package com.example.test.builders;
|
|
368
|
+
|
|
369
|
+
import com.example.domain.model.User;
|
|
370
|
+
|
|
371
|
+
public class UserTestBuilder {
|
|
372
|
+
|
|
373
|
+
private Long id = 1L;
|
|
374
|
+
private String email = "test@example.com";
|
|
375
|
+
private String username = "testuser";
|
|
376
|
+
private Boolean active = true;
|
|
377
|
+
|
|
378
|
+
public static UserTestBuilder aUser() {
|
|
379
|
+
return new UserTestBuilder();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
public UserTestBuilder withId(Long id) {
|
|
383
|
+
this.id = id;
|
|
384
|
+
return this;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
public UserTestBuilder withEmail(String email) {
|
|
388
|
+
this.email = email;
|
|
389
|
+
return this;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
public UserTestBuilder inactive() {
|
|
393
|
+
this.active = false;
|
|
394
|
+
return this;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
public User build() {
|
|
398
|
+
return User.builder()
|
|
399
|
+
.id(id)
|
|
400
|
+
.email(email)
|
|
401
|
+
.username(username)
|
|
402
|
+
.active(active)
|
|
403
|
+
.build();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Usage
|
|
408
|
+
User user = aUser()
|
|
409
|
+
.withEmail("custom@example.com")
|
|
410
|
+
.inactive()
|
|
411
|
+
.build();
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## Performance Testing with JMH
|
|
415
|
+
|
|
416
|
+
```java
|
|
417
|
+
package com.example.benchmark;
|
|
418
|
+
|
|
419
|
+
import org.openjdk.jmh.annotations.*;
|
|
420
|
+
import org.openjdk.jmh.runner.Runner;
|
|
421
|
+
import org.openjdk.jmh.runner.options.Options;
|
|
422
|
+
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
|
423
|
+
|
|
424
|
+
import java.util.concurrent.TimeUnit;
|
|
425
|
+
|
|
426
|
+
@BenchmarkMode(Mode.AverageTime)
|
|
427
|
+
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
428
|
+
@State(Scope.Benchmark)
|
|
429
|
+
@Fork(value = 2, warmups = 1)
|
|
430
|
+
@Warmup(iterations = 3)
|
|
431
|
+
@Measurement(iterations = 5)
|
|
432
|
+
public class UserServiceBenchmark {
|
|
433
|
+
|
|
434
|
+
private UserService userService;
|
|
435
|
+
|
|
436
|
+
@Setup
|
|
437
|
+
public void setup() {
|
|
438
|
+
// Initialize test data
|
|
439
|
+
userService = new UserService();
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
@Benchmark
|
|
443
|
+
public void benchmarkFindUser() {
|
|
444
|
+
userService.findById(1L);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
public static void main(String[] args) throws Exception {
|
|
448
|
+
Options opt = new OptionsBuilder()
|
|
449
|
+
.include(UserServiceBenchmark.class.getSimpleName())
|
|
450
|
+
.build();
|
|
451
|
+
new Runner(opt).run();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Test Containers Shared Instance
|
|
457
|
+
|
|
458
|
+
```java
|
|
459
|
+
package com.example.test;
|
|
460
|
+
|
|
461
|
+
import org.springframework.test.context.DynamicPropertyRegistry;
|
|
462
|
+
import org.springframework.test.context.DynamicPropertySource;
|
|
463
|
+
import org.testcontainers.containers.PostgreSQLContainer;
|
|
464
|
+
|
|
465
|
+
public abstract class AbstractIntegrationTest {
|
|
466
|
+
|
|
467
|
+
static final PostgreSQLContainer<?> postgres;
|
|
468
|
+
|
|
469
|
+
static {
|
|
470
|
+
postgres = new PostgreSQLContainer<>("postgres:16-alpine")
|
|
471
|
+
.withReuse(true);
|
|
472
|
+
postgres.start();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
@DynamicPropertySource
|
|
476
|
+
static void configureProperties(DynamicPropertyRegistry registry) {
|
|
477
|
+
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
478
|
+
registry.add("spring.datasource.username", postgres::getUsername);
|
|
479
|
+
registry.add("spring.datasource.password", postgres::getPassword);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## Quick Reference
|
|
485
|
+
|
|
486
|
+
| Annotation | Purpose |
|
|
487
|
+
|-----------|---------|
|
|
488
|
+
| `@Test` | Mark test method |
|
|
489
|
+
| `@BeforeEach` | Run before each test |
|
|
490
|
+
| `@AfterEach` | Run after each test |
|
|
491
|
+
| `@DisplayName` | Readable test name |
|
|
492
|
+
| `@ParameterizedTest` | Data-driven tests |
|
|
493
|
+
| `@ExtendWith` | Register extensions |
|
|
494
|
+
| `@SpringBootTest` | Full application context |
|
|
495
|
+
| `@WebMvcTest` | Test MVC layer only |
|
|
496
|
+
| `@DataJpaTest` | Test repository layer |
|
|
497
|
+
| `@MockBean` | Mock Spring bean |
|
|
498
|
+
| `@WithMockUser` | Mock authenticated user |
|
|
499
|
+
| `assertThat()` | AssertJ fluent assertions |
|
|
500
|
+
| `verify()` | Mockito verification |
|