plugins/github-copilot-modernization/skills/modernization-integration-tests/SKILL.md
Run multi-layer integration tests for modernized Java applications. Supports 4 layers - Layer 1 (TestContainers), Layer 2 (Smoke Tests), Layer 3 (Azure Integration), Layer 4 (Behavioral Comparison). Java projects only - skip if source code is not Java. Triggers: "generate integration tests", "add integration tests", "create Layer 1 tests", "create Layer 2 tests" NOT for: unit tests, performance tests, load tests.
npx skillsauth add microsoft/github-copilot-modernization modernization-integration-testsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill supports Java projects only. If the source code is not Java (e.g., .NET, Python, Node.js), skip test generation and report that integration tests are not supported for this language.
.github/integration-testsRead references/layer1-local-integration.md first, then create TestContainers-based integration test classes.
Read references/layer2-smoke-tests.md first. Layer 2 uses shell-based smoke tests with docker-compose, NOT JUnit test classes. Follow the exact multi-commit workflow (artifacts → auth → restore) documented in the reference file.
Read references/layer3-azure-integration.md first, then create integration test classes that connect to real Azure services.
Read references/layer4-behavioral-comparison.md first, then create comparison tests that validate behavior matches between old and new implementations.
{modernization-work-folder}/integration-test-plan.md that outlines:{modernization-work-folder}/integration-test-summary.md that documents:CRITICAL - Read Reference Docs First:
Analyze the project if integration tests have covered all components, if not DO ADD new integration tests by the following principles:
L1Test for Layer 1, L3Test for Layer 3, L4Test for Layer 4). Layer 2 does not use test classes.mvn verify (or equivalent build command) discovers and runs all tests without extra flags. If tests require -Dtest=... to be found, the build configuration is wrong.@Test annotation must be on a working test method.Add Layer 1 local integration tests). Generate runner scripts and include them in the same commit.When multiple layers coexist in the same project, tests must be distinguishable. Every layer MUST use a distinct class name suffix AND tag/category so tests from different layers never interfere with each other.
| Layer | Class Name Suffix | Example Class Name |
|-------|-------------------|--------------------|
| 1 | L1Test | BlobStorageL1Test, OrderServiceL1Test |
| 2 | N/A - No test classes | Layer 2 uses shell-based smoke tests, not test classes. See references/layer2-smoke-tests.md |
| 3 | L3Test | AzureSqlL3Test, BlobStorageL3Test |
| 4 | L4Test | OrderApiL4Test, UserServiceL4Test |
Test classes for Layers 1, 3, 4 MUST be annotated with a layer-specific tag so the runner script can filter precisely. Layer 2 does not use test classes (see references/layer2-smoke-tests.md).
| Layer | JUnit 5 | JUnit 4 |
|-------|---------|---------|
| 1 | @Tag("Layer1") | @Category(Layer1.class) |
| 2 | N/A - Shell-based | N/A - Shell-based |
| 3 | @Tag("Layer3") | @Category(Layer3.class) |
| 4 | @Tag("Layer4") | @Category(Layer4.class) |
Rule: Never rely solely on class name patterns for filtering. Always use tags/categories as the primary filter mechanism.
This is the most important rule in this entire skill — it applies to ALL layers.
Integration tests MUST use real TestContainers for layer 1 and 2 and real cloud services for Layer 3 for every migrated dependency. Do NOT mock or @MockBean the SDK client that the migrated code uses (e.g., ServiceBusTemplate, ServiceBusSenderClient, BlobServiceClient, RedisTemplate, DataSource). Instead, spin up a real container and wire the application's own service to it.
// ❌ WRONG — mocks the migrated service and SDK clients, tests unchanged code instead
@SpringBootTest
@ActiveProfiles("test")
class MyAppL1Test {
@MockBean private MessageService messageService; // THE MIGRATED CLASS — never tested!
@MockBean private ServiceBusSenderClient senderClient; // should be from real emulator
@MockBean private TokenCredential tokenCredential; // should be from emulator config
@Autowired private UserRepository userRepo; // unchanged code
@Test void testUserCrud() {
userRepo.save(new User("test")); // tests unchanged code, NOT the migration
}
}
// ✅ RIGHT — uses real Service Bus emulator, ALL beans wired from containers, tests through migrated service
@SpringBootTest
@ActiveProfiles("test")
@Testcontainers
class MyAppL1Test {
@Container static final GenericContainer<?> SERVICE_BUS = ...; // real emulator
// No @MockBean at all — all beans come from containers + @DynamicPropertySource
@Autowired private MessageService messageService; // THE MIGRATED CLASS — tested for real!
@DynamicPropertySource
static void props(DynamicPropertyRegistry registry) {
registry.add("spring.cloud.azure.servicebus.connection-string", () -> getConnectionString());
// ... other container-derived properties
}
@Test void testSendMessage() {
messageService.sendMessage("queue", "Hello"); // exercises the actual migrated code
}
}
When integration tests fail during execution, use this framework to determine whether to fix the test code or the source code:
Business Logic Violations
Test Implementation Issues
Test Failure
│
├─ Does test model realistic business scenario?
│ ├─ No → Fix Test Code
│ └─ Yes ↓
│
├─ Does source code violate business rules?
│ ├─ Yes → Fix Source Code
│ └─ No ↓
│
├─ Is test setup and environment correct?
│ ├─ No → Fix Test Code
│ └─ Yes ↓
│
└─ Does error show integration/logic problem?
├─ Yes → Fix Source Code
└─ No → Fix Test Code
After all tests are written, executed, and fixed to pass, generate a fixed runner script so users can re-run integration tests with a single command regardless of project type.
| Layer | Script Path | Command (Unix) | Command (Windows) |
|-------|-------------|----------------|--------------------||
| 1 | {modernization-work-folder}/integration-tests/run-layer1-tests.sh / .ps1 | bash {modernization-work-folder}/integration-tests/run-layer1-tests.sh | powershell {modernization-work-folder}/integration-tests/run-layer1-tests.ps1 |
| 2 | {modernization-work-folder}/integration-tests/run-layer2-tests.sh / .ps1 | bash {modernization-work-folder}/integration-tests/run-layer2-tests.sh | powershell {modernization-work-folder}/integration-tests/run-layer2-tests.ps1 |
| 3 | {modernization-work-folder}/integration-tests/run-layer3-tests.sh / .ps1 | bash {modernization-work-folder}/integration-tests/run-layer3-tests.sh | powershell {modernization-work-folder}/integration-tests/run-layer3-tests.ps1 |
| 4 | {modernization-work-folder}/integration-tests/run-layer4-tests.sh / .ps1 | bash {modernization-work-folder}/integration-tests/run-layer4-tests.sh | powershell {modernization-work-folder}/integration-tests/run-layer4-tests.ps1 |
.sh and .ps1 variants for cross-platform support.✅ Layer 1 integration tests PASSED❌ Layer 1 integration tests FAILEDLayers 1, 3, 4 use tag/category filters to execute test classes. Layer 2 uses shell commands (see references/layer2-runner-script-templates.md).
| Layer | Maven | Gradle |
|-------|-------|--------|
| 1 | mvn verify -Dgroups=Layer1 | ./gradlew test -Dgroups=Layer1 |
| 2 | Shell-based smoke tests | Shell-based smoke tests |
| 3 | mvn verify -Dgroups=Layer3 | ./gradlew test -Dgroups=Layer3 |
| 4 | mvn verify -Dgroups=Layer4 | ./gradlew test -Dgroups=Layer4 |
#!/bin/bash
set -euo pipefail
# --- Auto-generated integration test runner ---
# Project type: <detected>
# Generated on: <date>
# Verify prerequisites
if ! docker info > /dev/null 2>&1; then
echo "ERROR: Docker is not running. Please start Docker and try again."
exit 1
fi
# Run integration tests (project-specific command is embedded here)
# IMPORTANT: Always filter by the layer-specific tag to avoid running other layers' tests
# Test output (including any failure logs) goes directly to the console.
cd "$(dirname "$0")/../.."
<project-specific-test-command>
# e.g., mvn verify -Dgroups=Layer1, ./gradlew test -Dgroups=Layer1
TEST_EXIT=$?
# --- Print summary ---
echo ""
echo "========================================"
if [ $TEST_EXIT -eq 0 ]; then
echo "✅ Layer 1 integration tests PASSED"
else
echo "❌ Layer 1 integration tests FAILED"
fi
echo "========================================"
exit $TEST_EXIT
Note to implementers: Replace
<project-specific-test-command>with the real test command for the detected project type (Maven/Gradle). The test runner's own console output already includes detailed results — the script just appends a clear pass/fail signal at the end.
Integration Test Plan: Create and output a plan file at {modernization-work-folder}/integration-test-plan.md that includes:
All tests for the requested layer run and pass, show the running results to the user
Test results are reported with clear pass/fail status
Any failures are properly analyzed and resolved (see Handling Test Failures section)
Test artifacts (logs, screenshots, comparison reports) are saved
Version Control: Commit changes separately for each layer with meaningful commit messages. Do not combine changes from different layers into a single commit.
Add Layer 1 local integration tests)git add commands. Do not force-add files. If files in {modernization-work-folder} are ignored by the project's .gitignore, respect that.Integration Test Summary: Create and output a summary file at {modernization-work-folder}/integration-test-summary.md that documents:
Runner Scripts: Generate standardized runner scripts at {modernization-work-folder}/integration-tests/run-layer{N}-tests.sh and .ps1 (see Standardized Runner Scripts section). The scripts must embed all project-specific commands so users always run the same fixed command. Include runner scripts in the layer's commit (for Layer 2, in the artifacts commit).
Resources:
development
Evaluates whether a user's modernization/rewrite request provides enough scenario context to proceed (e.g., target component library, screenshots, design system for frontend; API contract policy, data migration strategy for backend). Produces a deterministic clarity score, asks the user for missing required fields via a structured form, and writes a canonical `clarification.md` artifact consumed by all downstream agents. Triggers: "clarification gate", "scenario clarification", "elicit missing context", "evaluate prompt completeness", "ask user for screenshots / target library / design system". NOT for: feature specification (use feature-inventory), planning (use creating-implementation-plan), implementation (use implementing-code), or resolving spec-time `[NEEDS CLARIFICATION]` markers (those remain owned by feature-inventory).
tools
Lifecycle hooks for the modernize-rearchitecture coordinator. Defines hook points, registered actions, and execution rules.
development
Provides role charters (mission, ownership, core principles, quality bar) for a multi-agent coding team. Each charter defines the role's mission, ownership scope, core principle (boundary constraints), and quality bar. Most roles also include communication rules. Consumed by the coordinator during task decomposition to assign work to the correct role. Triggers: "look up role charter", "what does the architect own", "check role boundaries", "find team roles", "which role handles X", "list agent charters", "role responsibilities". NOT for: task decomposition (use breaking-down-tasks), implementation (use implementing-code), architecture analysis (use analyzing-architecture).
tools
Zero-dependency shell recon for any code repository — detect languages, count LOC, and report project scale. Pure POSIX find/wc or PowerShell, no Python or third-party tools required. Triggers: "how big is this project", "what languages", "project sizing", "repo recon", "LOC count", "scope check".