laravel-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Laravel 13 Testing — Pest PHP 4 & PHPUnit 12

Laravel 13 测试 — Pest PHP 4 & PHPUnit 12

Supports both Pest PHP 4 and PHPUnit 12. See Framework Detection below.
PHPUnit version note: Laravel 13 ships with
phpunit/phpunit: ^12.5.12
in its default
composer.json
. All patterns in this skill are compatible with PHPUnit 11, 12, and 13.
Comprehensive testing guide for Laravel 13 applications. Contains 24 rules across 6 categories for writing fast, readable, and reliable tests. Supports both Pest PHP 4 and PHPUnit 12 (Laravel 13 default).
同时支持Pest PHP 4和PHPUnit 12。 详见下方的框架检测部分。
PHPUnit版本说明: Laravel 13在默认的
composer.json
中附带
phpunit/phpunit: ^12.5.12
。本技能中的所有规则均兼容PHPUnit 11、12和13版本。
Laravel 13应用的全面测试指南。包含6个分类下的24条规则,用于编写快速、易读且可靠的测试。同时支持Pest PHP 4PHPUnit 12(Laravel 13默认测试框架)。

Framework Detection

框架检测

Before writing or reviewing any test code, detect which testing framework the project uses:
在编写或评审任何测试代码之前,请先检测项目使用的测试框架:

Step 1 — Check composer.json

步骤1 — 检查composer.json

bash
undefined
bash
undefined

Look for these in require-dev:

在require-dev中查找以下内容:

"pestphp/pest" → Pest

"pestphp/pest" → 使用Pest

"phpunit/phpunit" (without pest) → PHPUnit

"phpunit/phpunit"(无pest依赖)→ 使用PHPUnit


- If `pestphp/pest` is present → **use Pest syntax**
- If only `phpunit/phpunit` is present → **use PHPUnit syntax**
- If both are present → **Pest takes priority** (Pest runs on top of PHPUnit)

- 若存在`pestphp/pest` → **使用Pest语法**
- 若仅存在`phpunit/phpunit` → **使用PHPUnit语法**
- 若两者都存在 → **优先使用Pest**(Pest基于PHPUnit运行)

Step 2 — Check for tests/Pest.php

步骤2 — 检查是否存在tests/Pest.php

  • If
    tests/Pest.php
    exists → Pest is configured, use Pest syntax
  • tests/Pest.php
    文件存在 → 已配置Pest,使用Pest语法

Step 3 — If still unclear, ask the user

步骤3 — 若仍不明确,询问用户

"I couldn't detect the testing framework. Does this project use Pest PHP or PHPUnit?"

"我无法检测到测试框架。该项目使用Pest PHP还是PHPUnit?"

Syntax Reference

语法参考

Test Declaration

测试声明

PestPHPUnit
Test function
test('...', fn() => ...)
public function test_...(): void
Readable name
it('...', fn() => ...)
#[Test] public function it_...()
Grouping
describe('...', fn() => ...)
Test class name / nested classes
Trait application
uses(RefreshDatabase::class)
use RefreshDatabase;
inside class
Before each
beforeEach(fn() => ...)
protected function setUp(): void
After each
afterEach(fn() => ...)
protected function tearDown(): void
Parameterised
->with([...])
#[DataProvider]
attribute
Global setup
uses(...)->in('Feature')
in
Pest.php
Base
TestCase
class
PestPHPUnit
测试函数
test('...', fn() => ...)
public function test_...(): void
可读命名
it('...', fn() => ...)
#[Test] public function it_...()
分组
describe('...', fn() => ...)
测试类名称 / 嵌套类
Trait应用
uses(RefreshDatabase::class)
在类内部使用
use RefreshDatabase;
每次测试前执行
beforeEach(fn() => ...)
protected function setUp(): void
每次测试后执行
afterEach(fn() => ...)
protected function tearDown(): void
参数化测试
->with([...])
#[DataProvider]
属性
全局设置
Pest.php
中使用
uses(...)->in('Feature')
基础
TestCase

Core assertions (identical in both frameworks)

核心断言(两个框架中完全一致)

assertStatus
,
assertJson
,
assertJsonPath
,
assertDatabaseHas
,
assertModelExists
,
actingAs
,
Mail::fake()
,
Queue::fake()
,
Event::fake()
,
Notification::fake()
,
Storage::fake()
— all work the same in Pest and PHPUnit.

assertStatus
,
assertJson
,
assertJsonPath
,
assertDatabaseHas
,
assertModelExists
,
actingAs
,
Mail::fake()
,
Queue::fake()
,
Event::fake()
,
Notification::fake()
,
Storage::fake()
— 这些在Pest和PHPUnit中的用法完全相同。

When to Apply

适用场景

Reference these guidelines when:
  • Writing feature or unit tests for Laravel
  • Testing HTTP endpoints and API responses
  • Creating factories and test data
  • Asserting database state after operations
  • Faking Mail, Queue, Notification, or Event facades
  • Testing authenticated routes and API tokens
  • Organising tests with describe blocks, datasets, or test classes
在以下场景中参考本指南:
  • 为Laravel编写功能测试或单元测试
  • 测试HTTP端点和API响应
  • 创建工厂和测试数据
  • 验证操作后的数据库状态
  • 模拟Mail、Queue、Notification或Event Facade
  • 测试认证路由和API令牌
  • 使用describe块、数据集或测试类组织测试

Rule Categories by Priority

按优先级划分的规则分类

PriorityCategoryImpactPrefix
1HTTP & Feature TestsCRITICAL
http-
2Model FactoriesCRITICAL
factory-
3Database AssertionsHIGH
db-
4Faking ServicesHIGH
fake-
5Authentication TestingHIGH
auth-
6Test Organisation PatternsMEDIUM
pest-
优先级分类影响程度前缀
1HTTP & 功能测试关键
http-
2模型工厂关键
factory-
3数据库断言
db-
4服务模拟
fake-
5认证测试
auth-
6测试组织模式
pest-

Quick Reference

快速参考

1. HTTP & Feature Tests (CRITICAL)

1. HTTP & 功能测试(关键)

  • http-test-structure
    - Arrange/Act/Assert with factories — Pest + PHPUnit examples
  • http-assert-response
    - assertStatus, assertJson, assertRedirect, assertJsonMissing
  • http-assert-json-fluent
    - Fluent assertJson with AssertableJson closure
  • http-refresh-database
    - RefreshDatabase vs DatabaseTransactions — when to use each
  • http-test-structure
    - 结合工厂使用Arrange/Act/Assert模式 — 含Pest + PHPUnit示例
  • http-assert-response
    - assertStatus、assertJson、assertRedirect、assertJsonMissing
  • http-assert-json-fluent
    - 使用AssertableJson闭包的流畅式assertJson
  • http-refresh-database
    - RefreshDatabase与DatabaseTransactions的对比 — 何时使用各自

2. Model Factories (CRITICAL)

2. 模型工厂(关键)

  • factory-define
    - Define factories with typed fake data and PHP 8.3 syntax
  • factory-states
    - Factory states for distinct test scenarios
  • factory-sequences
    - sequence() for varied data across multiple records
  • factory-relationships
    - has(), for(), recycle(), afterCreating()
  • factory-define
    - 使用类型化假数据和PHP 8.3语法定义工厂
  • factory-states
    - 用于不同测试场景的工厂状态
  • factory-sequences
    - 使用sequence()生成多条不同数据记录
  • factory-relationships
    - has()、for()、recycle()、afterCreating()

3. Database Assertions (HIGH)

3. 数据库断言(高)

  • db-assert-has
    - assertDatabaseHas, assertModelExists for presence checks
  • db-assert-missing
    - assertDatabaseMissing, assertModelMissing for deletion
  • db-assert-soft-deletes
    - assertSoftDeleted, trashed() factory state
  • db-assert-has
    - 使用assertDatabaseHas、assertModelExists检查存在性
  • db-assert-missing
    - 使用assertDatabaseMissing、assertModelMissing检查删除
  • db-assert-soft-deletes
    - assertSoftDeleted、trashed()工厂状态

4. Faking Services (HIGH)

4. 服务模拟(高)

  • fake-mail
    - Mail::fake(), assertSent vs assertQueued, assertNothingSent
  • fake-queue
    - Queue::fake(), assertPushed, assertPushedOn
  • fake-notification
    - Notification::fake(), assertSentTo, assertCount
  • fake-event
    - Event::fake(), assertDispatched, assertNotDispatched
  • fake-storage
    - Storage::fake(), UploadedFile::fake(), assertExists
  • fake-ai-agent
    - Agent::fake(), assertPrompted, preventStrayPrompts (Laravel 13+)
  • fake-ai-media
    - Image::fake(), Audio::fake(), Transcription::fake() (Laravel 13+)
  • fake-ai-data
    - Embeddings::fake(), Reranking::fake(), Files::fake(), Stores::fake() (Laravel 13+)
  • fake-mail
    - Mail::fake()、assertSent与assertQueued对比、assertNothingSent
  • fake-queue
    - Queue::fake()、assertPushed、assertPushedOn
  • fake-notification
    - Notification::fake()、assertSentTo、assertCount
  • fake-event
    - Event::fake()、assertDispatched、assertNotDispatched
  • fake-storage
    - Storage::fake()、UploadedFile::fake()、assertExists
  • fake-ai-agent
    - Agent::fake()、assertPrompted、preventStrayPrompts(Laravel 13+)
  • fake-ai-media
    - Image::fake()、Audio::fake()、Transcription::fake()(Laravel 13+)
  • fake-ai-data
    - Embeddings::fake()、Reranking::fake()、Files::fake()、Stores::fake()(Laravel 13+)

5. Authentication Testing (HIGH)

5. 认证测试(高)

  • auth-acting-as
    - actingAs() for session/web authenticated tests
  • auth-sanctum
    - Sanctum::actingAs() for API token authentication
  • auth-acting-as
    - 使用actingAs()进行会话/网页认证测试
  • auth-sanctum
    - 使用Sanctum::actingAs()进行API令牌认证

6. Test Organisation Patterns (MEDIUM)

6. 测试组织模式(中)

  • pest-describe-it
    - describe()/it() (Pest) or test class organisation (PHPUnit)
  • pest-datasets
    - with() datasets (Pest) or #[DataProvider] (PHPUnit)
  • pest-hooks
    - beforeEach/afterEach (Pest) or setUp/tearDown (PHPUnit)
  • pest-describe-it
    - describe()/it()(Pest)或测试类组织(PHPUnit)
  • pest-datasets
    - with()数据集(Pest)或#[DataProvider](PHPUnit)
  • pest-hooks
    - beforeEach/afterEach(Pest)或setUp/tearDown(PHPUnit)

Essential Patterns

核心示例

Pest

Pest

php
<?php

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('authenticated user can create a post', function () {
    $user = User::factory()->create();

    $this->actingAs($user)
        ->postJson('/api/posts', ['title' => 'Hello World', 'body' => 'Content.'])
        ->assertStatus(201)
        ->assertJsonPath('data.title', 'Hello World');

    $this->assertDatabaseHas('posts', ['title' => 'Hello World', 'user_id' => $user->id]);
});
php
<?php

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('authenticated user can create a post', function () {
    $user = User::factory()->create();

    $this->actingAs($user)
        ->postJson('/api/posts', ['title' => 'Hello World', 'body' => 'Content.'])
        ->assertStatus(201)
        ->assertJsonPath('data.title', 'Hello World');

    $this->assertDatabaseHas('posts', ['title' => 'Hello World', 'user_id' => $user->id]);
});

PHPUnit

PHPUnit

php
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PostControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_authenticated_user_can_create_a_post(): void
    {
        $user = User::factory()->create();

        $this->actingAs($user)
            ->postJson('/api/posts', ['title' => 'Hello World', 'body' => 'Content.'])
            ->assertStatus(201)
            ->assertJsonPath('data.title', 'Hello World');

        $this->assertDatabaseHas('posts', ['title' => 'Hello World', 'user_id' => $user->id]);
    }
}
php
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PostControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_authenticated_user_can_create_a_post(): void
    {
        $user = User::factory()->create();

        $this->actingAs($user)
            ->postJson('/api/posts', ['title' => 'Hello World', 'body' => 'Content.'])
            ->assertStatus(201)
            ->assertJsonPath('data.title', 'Hello World');

        $this->assertDatabaseHas('posts', ['title' => 'Hello World', 'user_id' => $user->id]);
    }
}

How to Use

使用方法

Read individual rule files for detailed explanations and code examples.
Each rule file contains:
  • YAML frontmatter with metadata (title, impact, tags)
  • Brief explanation of why it matters
  • Bad Example with explanation
  • Good Example with both Pest and PHPUnit where syntax differs
  • Laravel 13 specific context and references
阅读单个规则文件以获取详细说明和代码示例。
每个规则文件包含:
  • 带有元数据(标题、影响程度、标签)的YAML前置内容
  • 简要说明该规则的重要性
  • 错误示例及解释
  • 正确示例(若语法不同,同时提供Pest和PHPUnit版本)
  • Laravel 13特定上下文和参考资料

Full Compiled Document

完整编译文档

For the complete guide with all rules expanded:
AGENTS.md
如需包含所有扩展规则的完整指南,请查看:
AGENTS.md