About laravel-testing
A testing skill for Laravel 13 projects using Pest and PHPUnit. It covers feature, unit, and architecture tests, plus HTTP and database assertions, mocks, fakes, console tests, and seeding attributes.
Key features
- 01Feature, unit, and architecture tests
- 02Pest syntax and datasets
- 03HTTP and database assertions
- 04Mocking and framework fakes
- 05Artisan tests and seeding attributes
Use cases
- 01Testing HTTP endpoints and JSON APIs
- 02Isolating service and policy logic
- 03Checking database state with factories
- 04Faking external services, mail, queues, and events
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ fusengine/ claude-plugins --skill laravel-testingAfter installing, type/laravel-testingin Claude Code to confirm it loaded.
Details
From the project READMELaravel Testing
Agent Workflow (MANDATORY)
Before ANY implementation, spawn 3 agents in parallel, one Agent call each with a name:
- fuse-ai-pilot:explore-codebase - Analyze existing test patterns
- fuse-ai-pilot:research-expert - Verify Pest/PHPUnit docs via Context7
- mcp__context7__query-docs - Check assertion and mocking patterns
After implementation, run fuse-ai-pilot:sniper for validation.
Overview
| Type | Purpose | Location |
|---|---|---|
| Feature | HTTP, full stack | tests/Feature/ |
| Unit | Isolated classes | tests/Unit/ |
| Arch | Code architecture | tests/Arch.php |
Decision Guide: Test Type
What to test?
├── HTTP endpoint → Feature test
├── Service/Policy logic → Unit test
├── Code structure → Arch test
├── External API → Mock with Http::fake()
├── Mail/Queue/Event → Use Fakes
└── Database state → assertDatabaseHas()
Decision Guide: Test Strategy
Coverage strategy?
├── Feature tests (70%) → Critical flows
├── Unit tests (25%) → Business logic
├── E2E tests (5%) → User journeys
└── Arch tests → Structural rules
Critical Rules
- Use RefreshDatabase for database isolation
- Use factories for test data (never raw inserts)
- Mock external services - Never call real APIs
- Test edge cases - Empty, null, boundaries
- Run parallel -
pest --parallelfor speed
Reference Guide
Pest Basics
| Topic | Reference | When to Consult |
|---|---|---|
| Pest Syntax | pest-basics.md | it(), test(), describe() |
| Datasets | pest-datasets.md | Data providers, hooks |
| Architecture | pest-arch.md | arch() tests |
HTTP Testing
| Topic | Reference | When to Consult |
|---|---|---|
| Requests | http-requests.md | GET, POST, headers |
| JSON API | http-json.md | API assertions |
| Authentication | http-auth.md | actingAs, guards |
| Assertions | http-assertions.md | Status, redirects |
Database Testing
| Topic | Reference | When to Consult |
|---|---|---|
| Basics | database-basics.md | RefreshDatabase |
| Factories | database-factories.md | Factory patterns |
| Assertions | database-assertions.md | DB assertions |
Mocking
| Topic | Reference | When to Consult |
|---|---|---|
| Services | mocking-services.md | Mock, spy |
| Fakes | mocking-fakes.md | Mail, Queue, Event |
| HTTP & Time | mocking-http.md | Http::fake, travel |
Other
| Topic | Reference | When to Consult |
|---|---|---|
| Console | console-tests.md | Artisan tests |
| Troubleshooting | troubleshooting.md | Common errors |
Templates
| Template | When to Use |
|---|---|
| FeatureTest.php.md | HTTP feature test |
| UnitTest.php.md | Service unit test |
| ArchTest.php.md | Architecture test |
| ApiTest.php.md | REST API test |
| PestConfig.php.md | Pest configuration |
Quick Reference
// Feature test
it('creates a post', function () {
$user = User::factory()->create();
$this->actingAs($user)
->postJson('/api/posts', ['title' => 'Test'])
->assertCreated()
->assertJsonPath('data.title', 'Test');
$this->assertDatabaseHas('posts', ['title' => 'Test']);
});
// With dataset
it('validates emails', function (string $email, bool $valid) {
// test logic
})->with([
['[email protected]', true],
['invalid', false],
]);
// Mock facade
Mail::fake();
// ... action ...
Mail::assertSent(OrderShipped::class);
Commands
# Run all tests
php artisan test
# Pest directly
./vendor/bin/pest
# Parallel execution
./vendor/bin/pest --parallel
# Filter by name
./vendor/bin/pest --filter "user can"
# Coverage
./vendor/bin/pest --coverage --min=80
# Profile slow tests
./vendor/bin/pest --profile
Best Practices
DO
- Use
RefreshDatabasetrait - Follow AAA pattern (Arrange-Act-Assert)
- Name tests descriptively
- Test one thing per test
- Use factories for data
DON'T
- Create test dependencies
- Call real external APIs
- Use production database
- Skip edge cases
Laravel 13 Notes
PHPUnit 12/13 + Pest 4/5
The Laravel 13 skeleton ships PHPUnit 12 (^12.5); the framework also accepts PHPUnit 13. Pest 5 (current, requires PHP 8.4+ and PHPUnit 13, plus pestphp/pest-plugin-laravel ^5.0 which needs Laravel ^13.23) — stay on Pest 4 (PHPUnit 12) if the app still runs PHP 8.3. PHP attributes replace docblock annotations.
use PHPUnit\Framework\Attributes\Test;
use Illuminate\Foundation\Testing\Attributes\Seed;
use Illuminate\Foundation\Testing\Attributes\Seeder;
#[Seed] // runs DatabaseSeeder
#[Seeder(UserSeeder::class)] // runs a targeted seeder
final class UserTest extends TestCase
{
#[Test]
public function it_creates_user(): void { /* ... */ }
}
Str factories reset
Laravel 13 resets custom Str factories (UUID / ULID / random string) during test teardown. Tests relying on a factory persisting across methods must set it in each test or setup hook.
#[UnitTest] (L13)
Illuminate\Foundation\Testing\Attributes\UnitTest on a test method skips booting the application for that test.
Migration from Pest 3 → 4
- Bump
pestphp/pestand all Pest plugins to^4.0(PHP 8.3+, PHPUnit 12) - Snapshot names changed: run
./vendor/bin/pest --update-snapshots pest-plugin-watchandpest-plugin-fakerare archived
Migration from Pest 4 → 5
- Requires PHP 8.4+; bump
pestphp/pestand all Pest plugins to^5.0(built on PHPUnit 13) - New in 5:
--tia(test impact analysis, local only), first-party PHPStan/Rector plugins, Agent and Evals plugins, time-balanced sharding