Skip to content
Back to skills

Php Testing

ASecurity

Use when writing/configuring tests on a non-Laravel PHP project — PHPUnit vs Pest. Do NOT use for Laravel test helpers or quality tooling (php-quality-tooling).

  • 29 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 6, 2026
ai-agentsgophpexpresstestingapidatabase

Works with

  • api
  • mcp

Security analysis

A100/100

Pro scans all 8 files and shows the line behind each finding

Scanned September 29, 2026

npx -y skills add fusengine/agents --skill php-testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Php Testing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Php Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/fusengine-php-testing/badge)](https://www.skillsdirectory.com/skills/fusengine-php-testing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: php-testing
description: Use when writing/configuring tests on a non-Laravel PHP project — PHPUnit vs Pest. Do NOT use for Laravel test helpers or quality tooling (php-quality-tooling).
versions:
  phpunit: "13"
  pest: "5"
user-invocable: true
references: references/choosing-framework.md, references/phpunit-12.md, references/pest-4.md, references/annotations-to-attributes.md, references/templates/phpunit-xml.md, references/templates/pest-setup.md, references/templates/test-doubles.md
related-skills: php-quality-tooling, php-language-modern
---

<objective>
Covers testing a framework-agnostic PHP project with PHPUnit 13 (class-based, xUnit-style, attributes only — annotations like @test/@dataProvider were removed in PHPUnit 12) or Pest 5 (closure-based, expressive, adds browser/architecture/mutation testing, built on PHPUnit 13), both of which run on PHPUnit's engine and require PHP 8.4+.

Includes a decision matrix for choosing between the two (team preference, not capability), plus templates for phpunit.xml, Pest.php setup, and test doubles (stubs, mocks, fixtures, coverage).

Do NOT use this skill for Laravel test helpers such as RefreshDatabase or HTTP testing — those are covered by laravel-expert's laravel-testing skill. Do NOT use it for static analysis or formatting tooling — that is php-quality-tooling.
</objective>


# PHP Testing

Two frameworks, one engine. Pest is a layer over PHPUnit — both need **PHP 8.4+**
and share the same runner and assertions underneath.

## Agent Workflow (MANDATORY)

Before ANY implementation, spawn 3 agents in parallel, one `Agent` call each with a `name`:

1. **fuse-ai-pilot:explore-codebase** - Detect existing framework (phpunit.xml vs Pest.php), test layout, PHP version
2. **fuse-ai-pilot:research-expert** - Verify latest PHPUnit 13 / Pest 5 docs via Context7/Exa
3. **mcp__context7__query-docs** - Check attribute names, test-double API, config schema

After implementation, run **fuse-ai-pilot:sniper** for validation.

---

## Overview

| Framework | Style | Strength |
|-----------|-------|----------|
| PHPUnit 13 | Class-based, xUnit | Enterprise baseline, explicit, widest tooling/CI support |
| Pest 5 | Closure-based, expressive | Modern DX, browser + arch + mutation testing, less boilerplate |

Pest 5 runs on PHPUnit 13's engine, so PHPUnit knowledge transfers directly. The
choice is about ergonomics and team preference, not capability.

---

## Critical Rules

1. **PHP 8.4+ required** - Both PHPUnit 13 and Pest 5 drop PHP 8.3 (stay on PHPUnit 12 / Pest 4 for 8.3)
2. **Attributes only, no annotations** - PHPUnit 12 **removed** docblock annotations (`@test`, `@dataProvider`)
3. **Data providers are `public static`** - Non-static providers no longer work
4. **`createStub()` is not configurable** - Configure expectations only on `createMock()`; `any()` is hard-deprecated in PHPUnit 13 — use a stub or a real count (`once()`, `exactly(n)`)
5. **One framework per project** - Pest or PHPUnit, not both driving the same suite
6. **Mock at boundaries** - Network/DB/clock, never internal implementation detail

---

## Decision Guide

```
Choosing a framework? (non-Laravel)
├── Enterprise / strict CI / mixed team → PHPUnit 13 (explicit, ubiquitous)
├── Modern DX, greenfield, small team → Pest 5 (concise, expressive)
├── Need browser / architecture / mutation testing out of the box → Pest 5
└── 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`

---

## Reference Guide

### Concepts

| Topic | Reference | Load when |
|-------|-----------|-----------|
| Framework choice | `references/choosing-framework.md` | Deciding PHPUnit vs Pest |
| PHPUnit 13 | `references/phpunit-12.md` | Writing PHPUnit tests |
| Pest 5 | `references/pest-4.md` | Writing Pest tests |
| Annotation migration | `references/annotations-to-attributes.md` | Upgrading pre-12 tests |

### Templates

| 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 |

---

## Quick Start

### PHPUnit 13

```php
use PHPUnit\Framework\TestCase;

final class GreeterTest extends TestCase
{
    public function testGreets(): void
    {
        $this->assertSame('Hi, Al', (new Greeter)->greet('Al'));
    }
}
```

### Pest 5

```php
it('greets', function () {
    expect((new Greeter)->greet('Al'))->toBe('Hi, Al');
});
```

---

## Best Practices

### DO
- Name tests by behavior (`testRejectsExpiredToken`), assert one behavior each
- Use `#[DataProvider]` with `public static` providers for table-driven tests
- Gate CI on an explicit coverage threshold, not a report

### DON'T
- Keep `@test` / `@dataProvider` annotations (removed in PHPUnit 12)
- Configure expectations on `createStub()` results
- Mock the class under test — mock its collaborators

Files in this skill

  • SKILL.md5 KB
  • references/annotations-to-attributes.md2.4 KB
  • references/choosing-framework.md2.1 KB
  • references/pest-4.md2.2 KB
  • references/phpunit-12.md2.6 KB
  • references/templates/pest-setup.md2.2 KB
  • references/templates/phpunit-xml.md2.2 KB
  • references/templates/test-doubles.md2.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…