Help us improve
Share bugs, ideas, or general feedback.
From test-writing
Generates Shopware-compliant PHPUnit unit tests for PHP classes in tests/unit/, skipping coverage-excluded or trivial ones, validating with PHPStan, ECS, and PHPUnit.
npx claudepluginhub shopwarelabs/ai-coding-tools --plugin test-writingHow this skill is triggered — by the user, by Claude, or both
Slash command
/test-writing:phpunit-unit-test-generationThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate Shopware-compliant PHPUnit unit tests that pass PHPStan and PHPUnit validation.
references/category-detection.mdreferences/common-patterns.mdreferences/essential-rules.mdreferences/output-format.mdreferences/shopware-stubs.mdreferences/test-requirement-rules.mdreferences/validation-error-mapping.mdtemplates/category-a-dto.mdtemplates/category-b-service.mdtemplates/category-c-flow.mdtemplates/category-d-dal.mdtemplates/category-e-exception.mdGenerates and validates PHPUnit unit tests for PHP classes with review-fix cycles using phpunit_run, phpstan_analyze, and ecs tools. For Shopware 6 unit test coverage.
Writes PHPUnit tests for PHP code: unit tests, mocking, data providers, test doubles, assertions, and TDD practices. Use for testing PHP apps including Magento.
PHPUnit testing framework conventions and practices. Invoke whenever task involves any interaction with PHPUnit — writing tests, configuring PHPUnit, data providers, mocking, assertions, debugging test failures, or coverage.
Share bugs, ideas, or general feedback.
Generate Shopware-compliant PHPUnit unit tests that pass PHPStan and PHPUnit validation.
Write ONLY to:
tests/unit/** - Unit test filesNEVER write to:
src/** - Source code (read-only)tests/integration/** - Out of scopeUse ONLY MCP tools for PHP validation (NEVER Bash commands):
| Instead of (Bash) | Use (MCP) |
|---|---|
vendor/bin/phpstan | mcp__plugin_dev-tooling_php-tooling__phpstan_analyze |
vendor/bin/phpunit | mcp__plugin_dev-tooling_php-tooling__phpunit_run |
vendor/bin/ecs | mcp__plugin_dev-tooling_php-tooling__ecs_check / ecs_fix |
composer phpstan:* | MCP equivalent |
MCP tools handle environment detection (native/docker/vagrant/ddev) automatically.
Before analyzing the source class, check if the project's phpunit.xml.dist (or phpunit.xml) excludes it from coverage. Files excluded from coverage do not need unit tests.
phpunit.xml.dist from the project root<exclude> rules inside the <coverage> or <source> section<directory suffix="X">path</directory> — excluded if file is under path AND filename ends with X<file>path/to/File.php</file> — excluded if relative path matches exactlyskip_type: coverage_excluded and reason: "Source file excluded from coverage by phpunit.xml.dist (<matched-rule>)"If phpunit.xml.dist is not found, skip this step.
Before generating any test, evaluate if the class/method requires one.
Quick check: Does the method body contain ONLY return <literal|constant|property|passthrough-new|delegation>?
skip_type: no_logic and reason describing the pattern (e.g., "Pure accessor - no logic to test")For detailed rules on what to test vs skip, see test-requirement-rules.md.
Read the target class to determine:
Use the decision tree to select the appropriate category:
Has constructor dependencies?
├── No → Is it an Exception class?
│ ├── Yes → Category E
│ └── No → Category A (DTO)
└── Yes → Uses EntityRepository?
├── Yes → Category D (DAL)
└── No → Implements EventSubscriberInterface or FlowAction?
├── Yes → Category C (Flow/Event)
└── No → Category B (Service)
For detailed category criteria, see category-detection.md.
Apply these mandatory conventions when generating tests.
| Rule | Requirement |
|---|---|
| File location | tests/unit/ mirroring src/ path |
| Class attribute | #[CoversClass(TargetClass::class)] required |
| Assertions | Use static:: not $this-> |
| Base class | Extend PHPUnit\Framework\TestCase |
| Method naming | test + Action + Condition + ExpectedResult |
| Attribute order | PHPDoc -> DataProvider -> TestDox -> method |
| One behavior | NO conditionals in tests |
TestDox MUST be a predicate phrase starting with an action verb:
StaticEntityRepository, StaticSystemConfigService, GeneratorFor complete rules, see essential-rules.md.
Based on category from Phase 1:
| Category | Template |
|---|---|
| A (DTO) | category-a-dto.md |
| B (Service) | category-b-service.md |
| C (Flow/Event) | category-c-flow.md |
| D (DAL) | category-d-dal.md |
| E (Exception) | category-e-exception.md |
{Module} - Core module (e.g., Content, Checkout, System){Submodule} - Submodule path (e.g., Product, Cart\LineItem){TargetClass} - Class name being tested{Entity} - Entity name for DAL tests{Method} - Method name being tested{Expected} - Expected outcome description{Condition} - Condition description{Exception} - Exception class nameWrite to correct location: tests/unit/{path matching src}/{ClassName}Test.php
CRITICAL: Use ONLY MCP tools for validation. NEVER use shell commands.
Prerequisite: The dev-tooling plugin must be installed (provides php-tooling MCP server). If unavailable, proceed to Phase 5 with status PARTIAL.
- [ ] PHPStan passes (0 errors)
- [ ] PHPUnit passes (all tests green)
- [ ] ECS passes (code style)
{
"paths": ["tests/unit/Path/To/GeneratedTest.php"],
"error_format": "json"
}
Zero errors = pass.
Apply fixes for common errors. See validation-error-mapping.md.
{
"paths": ["tests/unit/Path/To/GeneratedTest.php"],
"output_format": "result-only"
}
All tests passing = success. If tests fail, re-run without output_format to get failure details for Step 4.
Apply fixes for common failures. See validation-error-mapping.md.
Check for violations, then apply fixes if needed.
Loop through Steps 1-5 until all validations pass.
Maximum iterations: Stop after 3 failed attempts and proceed to Phase 5.
For output format and examples, see output-format.md.
| Condition | Status | skip_type |
|---|---|---|
| All validations pass | SUCCESS | — |
| Test generated, validation issues remain after 3 iterations | PARTIAL | — |
| File excluded from coverage in phpunit.xml.dist | SKIPPED | coverage_excluded |
| No testable logic (per Test Requirement Rules) | SKIPPED | no_logic |
| Invalid input (not a PHP class, file not found) | FAILED | — |
For detailed patterns and techniques, consult:
Category-specific test generation templates in templates/: