Laravel 单元测试入门指南

在 Laravel 中用 PHPUnit 写测试:创建与运行测试、HTTP 响应断言、数据库测试与假数据、Dusk 浏览器测试、Mock 外部 API,以及用 GitHub Actions 搭建 CI 测试流程。

最佳实践
测试检测与质量验证插画

本文依据官方文档整理,未执行运行验证或性能基准。代码片段展示局部用法,业务函数、数据和环境需按项目补齐;版本与配置以所引文档为准。

直接回答:Laravel 开箱即集成了 PHPUnit,项目创建后即可直接编写两类测试——单元测试聚焦类中的单个方法,功能测试验证多个类协作完成的完整特性;配合框架自带的 HTTP 断言、数据库工具和 Mock 门面,可以覆盖从模型到接口的全链路。

Laravel 测试的两个层次

类型 关注点 典型位置
单元测试(Unit) 单个方法的逻辑正确性 tests/Unit
功能测试(Feature) 多个组件协作的特性行为 tests/Feature

Laravel 新建项目自带这两个目录和示例用例,php artisan test(或 ./vendor/bin/phpunit)即可运行。

创建测试

php artisan make:test OrderServiceTest --unit   # 单元测试
php artisan make:test OrderApiTest              # 功能测试(默认)

一条典型的单元测试:

public function test_order_total_is_sum_of_items(): void
{
    $service = new OrderService();
    $this->assertEquals(300, $service->total([100, 200]));
}

PHPUnit 提供了大量断言:assertTrue、assertCount、assertInstanceOf;异常预期常用 $this->expectException(...) 等,绝大多数场景不用手写 if-else。

测试 HTTP 响应

功能测试里最常用的是 HTTP 断言链:

public function test_create_order(): void
{
    $response = $this->postJson('/api/orders', ['sku' => 'A1', 'qty' => 2]);

    $response->assertStatus(201)
             ->assertJsonPath('data.sku', 'A1');
}

getJson、postJson、putJson、deleteJson 覆盖常见动词,断言可以连续检查状态码、JSON 结构、Header 和 Session。

数据库测试与假数据

功能测试类继承 Tests\TestCase 并加 RefreshDatabase,框架按数据库状态迁移并通常用事务隔离。务必使用专用测试库,不能指向生产;普通 PHPUnit Unit 测试并未引导 Laravel。SQLite 与生产数据库方言不同,不能替代同引擎集成测试:

use Illuminate\Foundation\Testing\RefreshDatabase;

class OrderTest extends TestCase
{
    use RefreshDatabase;

    public function test_order_is_stored(): void
    {
        Order::factory()->create(['total' => 99]);
        $this->assertDatabaseHas('orders', ['total' => 99]);
    }
}

factory() 结合 Faker 能批量生成逼真假数据,避免手写一堆 INSERT。

浏览器测试:Laravel Dusk

需要验证真实浏览器行为(JS 交互、页面跳转)时用 Dusk:它驱动真实 Chrome 执行点击、填表、截图断言。适合覆盖少量关键用户路径,不建议大规模铺开——浏览器测试慢且脆。

Mock 外部 API

单元/常规功能测试可 Mock 第三方;另以经授权的沙箱集成测试验证真实契约:

Http::fake([
    'api.payment.com/*' => Http::response(['status' => 'ok'], 200),
]);

Http::fake 只拦截 Laravel HTTP Client 发出的请求;可配 Http::preventStrayRequests 防止未匹配请求意外出网,还能用 Http::assertSent 断言请求体是否正确。Mail::fake()、Queue::fake()、Event::fake() 同理。

接入 GitHub Actions

- name: Run tests
  run: php artisan test

把测试挂进 push/PR 触发的 workflow,配合 PHP 版本矩阵,就得到了最基本的 CI 门禁:测试不过,代码不合。

常见问题(FAQ)

Q:单元测试和功能测试的比例怎么把握?
A:以金字塔为参考:大量单元测试打底,适量功能测试覆盖关键流程,极少量 Dusk 覆盖核心页面。功能测试占比过高会拖慢套件且定位困难。

Q:测试连真实数据库可以吗?
A:可以但要隔离:专用测试库 + RefreshDatabase。数据库特性测试优先使用与生产同引擎的隔离实例;SQLite 只用于明确不依赖方言差异的路径。

Q:Dusk 测试在 CI 里跑不动怎么办?
A:CI 需要无头 Chrome 和 chromedriver,GitHub Actions 有现成方案。若维护成本过高,把 Dusk 缩到 3~5 条最关键路径即可。

官方参考

资料核对日期:2026-09-29。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台