Write unit and integration tests for PHP applications with PHPUnit and Pest. Use when writing PHPUnit unit tests or integration tests for PHP applications.
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.
[](https://www.skillsdirectory.com/skills/hoangnguyen0403-php-testing)
---
name: php-testing
description: Write unit and integration tests for PHP applications with PHPUnit and Pest. Use when writing PHPUnit unit tests or integration tests for PHP applications.
metadata:
triggers:
files:
- 'tests/**/*.php'
- 'phpunit.xml'
keywords:
- phpunit
- pest
- mock
- assert
- tdd
---
# PHP Testing
## **Priority: P1 (HIGH)**
## Core Rule Anchors
- **`[BE-TEST-01]` Parameterized Tests for Equivalent Cases**: Prefer `#[DataProvider]` (PHPUnit) or `dataset` (Pest) when methods have multiple equivalent inputs or boundary permutations. Distinct scenarios may stay separate test methods. Reviewers must not demand parameterized rewrites without a behavioral gap.
- **`[BE-TEST-02]` Ban on Brittle DB Mock String Matching**: Do not use string-matching mocks for raw SQL queries. Test pure domain calculations directly, or use SQLite in-memory / real DB for database repository verification.
- **`[BE-TEST-03]` Ban on Shallow Assertions**: Never assert only `assertNotNull($result)` without inspecting domain fields, status codes, and invariants.
- **`[BE-TEST-04]` Ban on Pass-Through Interface Mocks**: Repositories and service handlers must test contract compliance and error mapping. Ban 1:1 pass-through mock echoing without contract assertions.
- **`[BE-TEST-05]` Bug-First Regression Lock**: Every PR fixing a bug ticket or with title `fix(...)` must introduce a test reproducing the defect prior to the fix.
## Write Tests with PHPUnit and Pest
- **Standards**: Use **`PHPUnit`** (9/10+) or **`Pest`**. Organize into **`Unit/`**, **`Integration/`**, and **`Feature/`**. Class names should extend **`TestCase`**.
- **TDD Workflow (`[BE-TEST-05]`)**: Follow **Red-Green-Refactor**. Write failing test first, implement minimal logic, then refactor.
- **Fluent Assertions (`[BE-TEST-03]`)**: Use **`assertSame`** (`===`) over `assertEquals` to avoid type coercion. Also use **`assertCount()`** and **`assertMatchesRegularExpression()`**. Avoid shallow assertions.
- **Data Providers (`[BE-TEST-01]`)**: Use **`#[DataProvider('statusProvider')]`** (PHPUnit 10+) or **`dataset`** (Pest).
- **Mocking & Isolation (`[BE-TEST-02]`, `[BE-TEST-04]`)**: Use **`createMock()`** for dependencies; ban 1:1 pass-through mock echoing. Ensure tests are independent and repeatable. DB tests must use **`Transactions`** or **`SQLite :memory:`**.
- **Coverage**: Coverage is diagnostic and project-configured; verify risk-weighted critical paths rather than padding code for an arbitrary percentage.
## Anti-Patterns
- **`[BE-TEST-01]` Stylistic parameterized rewrites**: Do not demand data provider rewrites without a behavioral gap.
- **`[BE-TEST-02]` Brittle DB mock string matching**: Do not match SQL strings in mocks.
- **`[BE-TEST-03]` Shallow assertions**: Never assert only `assertNotNull` without domain payload checks.
- **`[BE-TEST-04]` Pass-through mock echoing**: Ban 1:1 mock echoing without contract assertions.
- **`[BE-TEST-05]` Bug fix without reproduction test**: Ban bug fixes without a reproduction test.
- **No testing private methods**: Test through public interfaces only.
- **No over-mocking internals**: Mock only external boundaries.
- **No real network/DB in unit tests**: Use in-memory databases or mocks.
- **No coverage-metric chasing**: Prioritize meaningful assertions over arbitrary percentage metrics.
## References
- [Testing Patterns & Mocks](references/implementation.md)
## Canonical response anchors
When this skill applies, preserve the following domain terminology or equivalent concrete examples in the answer when relevant:
- Define a static method returning test cases as arrays,method
- independent
- type coercion