plugins/php-expert/skills/php-testing/SKILL.md
Use when writing or configuring tests on a framework-agnostic PHP project and choosing between PHPUnit and Pest. Covers PHPUnit 12 attributes, Pest 4, test doubles, fixtures, and coverage. Do NOT use for Laravel test helpers (RefreshDatabase, HTTP tests → laravel-expert laravel-testing) or quality tooling (PHPStan/Rector/Fixer → php-quality-tooling).
npx skillsauth add fusengine/agents php-testingInstall 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.
Two frameworks, one engine. Pest is a layer over PHPUnit — both need PHP 8.3+ and share the same runner and assertions underneath.
Before ANY implementation, use TeamCreate to spawn 3 agents:
After implementation, run fuse-ai-pilot:sniper for validation.
| Framework | Style | Strength | |-----------|-------|----------| | PHPUnit 12 | Class-based, xUnit | Enterprise baseline, explicit, widest tooling/CI support | | Pest 4 | Closure-based, expressive | Modern DX, browser + arch + mutation testing, less boilerplate |
Pest 4 runs on PHPUnit's engine, so PHPUnit knowledge transfers directly. The choice is about ergonomics and team preference, not capability.
@test, @dataProvider)public static - Non-static providers no longer workcreateStub() is not configurable - Configure expectations only on createMock()Choosing a framework? (non-Laravel)
├── Enterprise / strict CI / mixed team → PHPUnit 12 (explicit, ubiquitous)
├── Modern DX, greenfield, small team → Pest 4 (concise, expressive)
├── Need browser / architecture / mutation testing out of the box → Pest 4
└── Migrating a large PHPUnit suite → stay PHPUnit, or drift-migrate to Pest
Honest note: PHPUnit is the enterprise/CI baseline; Pest has strong community momentum but that trend is not normative. Either is a correct, well-supported choice — pick per team, not per hype.
→ Full matrix in references/choosing-framework.md
| Topic | Reference | Load when |
|-------|-----------|-----------|
| Framework choice | references/choosing-framework.md | Deciding PHPUnit vs Pest |
| PHPUnit 12 | references/phpunit-12.md | Writing PHPUnit tests |
| Pest 4 | references/pest-4.md | Writing Pest tests |
| Annotation migration | references/annotations-to-attributes.md | Upgrading pre-12 tests |
| Template | Use Case |
|----------|----------|
| references/templates/phpunit-xml.md | phpunit.xml + first TestCase |
| references/templates/pest-setup.md | Pest.php + first Pest tests |
| references/templates/test-doubles.md | Stubs, mocks, fixtures, coverage |
use PHPUnit\Framework\TestCase;
final class GreeterTest extends TestCase
{
public function testGreets(): void
{
$this->assertSame('Hi, Al', (new Greeter)->greet('Al'));
}
}
it('greets', function () {
expect((new Greeter)->greet('Al'))->toBe('Hi, Al');
});
testRejectsExpiredToken), assert one behavior each#[DataProvider] with public static providers for table-driven tests@test / @dataProvider annotations (removed in PHPUnit 12)createStub() resultstesting
Copy self-audit and ban-lists — filler verbs/hype adjectives, slop placeholder names, fake-precise numbers, Title Case headlines, humor in error copy ('Oops!'), em-dash crutch, one copy register per page.
development
Logged-in web apps — dashboards, auth flows, settings, onboarding, data tables, command palettes, modals, toasts. Register `product`: density and glance-speed over marketing polish, no hero/CTA-tricks, every data surface covers empty/loading/error explicitly, tables and dataviz follow preattentive-processing rules.
development
Marketing sites, landing pages, campaign pages — register `brand` (design IS the product). Structure comes from the register's POV + a macrostructure pick, never from copying an inspiration site's section flow. Hero discipline, deviated section order, asymmetric grids, and a silhouette lookalike-test gate before ship.
development
Token-strategy core — OKLCH color rules, neutral tinting, accent-commitment levels, type scale, 8pt spacing grid, touch targets, and the canonical output format of design-system.md (the file the harness gates on). This is routing step 1 of design-method/SKILL.md — read it before design-web/design-webapp/design-ios/design-android, before picking or auditing a single color/type/spacing value.