跳转至内容

测试:入门指南

简介

Laravel 在设计时就考虑到了测试。事实上,它开箱即用支持 PestPHPUnit 测试,并且你的应用程序中已经预置了 phpunit.xml 文件。该框架还提供了便捷的辅助方法,让你可以直观地测试应用程序。

默认情况下,你的应用程序 tests 目录包含两个子目录:FeatureUnit。单元测试(Unit tests)专注于代码中极小且独立的部分。实际上,大多数单元测试可能只针对单个方法。“Unit”测试目录下的测试不会启动完整的 Laravel 应用程序,因此无法访问数据库或其他框架服务。

功能测试(Feature tests)可以测试更大范围的代码,包括多个对象之间的交互,甚至是发送到 JSON 端点的完整 HTTP 请求。通常情况下,大部分测试应该是功能测试。这类测试最能确保整个系统按预期运行。

FeatureUnit 测试目录中都提供了一个 ExampleTest.php 文件。安装新的 Laravel 应用程序后,执行 vendor/bin/pestvendor/bin/phpunitphp artisan test 命令即可运行测试。

环境

运行测试时,由于 phpunit.xml 文件中定义了环境变量,Laravel 会自动将配置环境设置为 testing。Laravel 还会自动将 Session 和缓存配置为 array 驱动,这样测试过程中就不会持久化任何 Session 或缓存数据。

你可以根据需要自由定义其他测试环境配置值。testing 环境变量可以在应用程序的 phpunit.xml 文件中进行配置,但在运行测试之前,请务必使用 config:clear Artisan 命令清除配置缓存!

.env.testing 环境文件

此外,你还可以在项目根目录下创建 .env.testing 文件。在运行 Pest 和 PHPUnit 测试或使用 --env=testing 选项执行 Artisan 命令时,该文件将取代 .env 文件被使用。

创建测试

要创建新的测试用例,请使用 make:test Artisan 命令。默认情况下,测试将被放置在 tests/Feature 目录中。

1php artisan make:test UserTest

如果你想在 tests/Unit 目录中创建测试,可以在执行 make:test 命令时使用 --unit 选项。

1php artisan make:test UserTest --unit

可以通过发布存根 (stub) 来自定义测试存根。

测试生成后,你可以像平时一样使用 Pest 或 PHPUnit 定义测试。要运行测试,请在终端执行 vendor/bin/pestvendor/bin/phpunitphp artisan test 命令。

1<?php
2 
3test('basic', function () {
4 expect(true)->toBeTrue();
5});
1<?php
2 
3namespace Tests\Unit;
4 
5use PHPUnit\Framework\TestCase;
6 
7class ExampleTest extends TestCase
8{
9 /**
10 * A basic test example.
11 */
12 public function test_basic_test(): void
13 {
14 $this->assertTrue(true);
15 }
16}

如果你在测试类中定义了自己的 setUp / tearDown 方法,请务必在父类上调用相应的 parent::setUp() / parent::tearDown() 方法。通常,你应该在自己的 setUp 方法开头调用 parent::setUp(),并在 tearDown 方法末尾调用 parent::tearDown()

运行测试

如前所述,编写完测试后,可以使用 pestphpunit 运行它们。

1./vendor/bin/pest
1./vendor/bin/phpunit

除了 pestphpunit 命令外,你还可以使用 test Artisan 命令来运行测试。Artisan 测试运行器提供了详细的测试报告,以简化开发和调试过程。

1php artisan test

所有可以传递给 pestphpunit 命令的参数,同样可以传递给 Artisan 的 test 命令。

1php artisan test --testsuite=Feature --stop-on-failure

并行运行测试

默认情况下,Laravel 和 Pest / PHPUnit 会在单个进程中按顺序执行测试。但是,你可以通过在多个进程中同时运行测试,大大缩短测试时间。首先,你需要安装 brianium/paratest Composer 包作为“dev”依赖。然后,在执行 test Artisan 命令时加上 --parallel 选项。

1composer require brianium/paratest --dev
2 
3php artisan test --parallel

默认情况下,Laravel 将创建与机器 CPU 核心数相当的进程数量。你也可以使用 --processes 选项来调整进程数。

1php artisan test --parallel --processes=4

并行运行测试时,某些 Pest / PHPUnit 选项(例如 --do-not-cache-result)可能不可用。

并行测试与数据库

只要你配置了主数据库连接,Laravel 就会自动为每个并行运行测试的进程处理测试数据库的创建和迁移。测试数据库将带有一个进程标识符后缀,该标识符在每个进程中都是唯一的。例如,如果你有两个并行测试进程,Laravel 将创建并使用 your_db_test_1your_db_test_2 作为测试数据库。

默认情况下,测试数据库在调用 test Artisan 命令后会持久存在,以便后续的 test 调用可以再次使用。不过,你可以使用 --recreate-databases 选项重新创建它们。

1php artisan test --parallel --recreate-databases

并行测试钩子

有时,你可能需要准备应用程序测试所需的某些资源,以便它们能被多个测试进程安全使用。

使用 ParallelTesting 门面(facade),你可以指定在进程或测试用例的 setUptearDown 时执行的代码。提供的闭包会接收 $token$testCase 变量,分别包含进程标识符和当前测试用例。

1<?php
2 
3namespace App\Providers;
4 
5use Illuminate\Support\Facades\Artisan;
6use Illuminate\Support\Facades\ParallelTesting;
7use Illuminate\Support\ServiceProvider;
8use PHPUnit\Framework\TestCase;
9 
10class AppServiceProvider extends ServiceProvider
11{
12 /**
13 * Bootstrap any application services.
14 */
15 public function boot(): void
16 {
17 ParallelTesting::setUpProcess(function (int $token) {
18 // ...
19 });
20 
21 ParallelTesting::setUpTestCase(function (int $token, TestCase $testCase) {
22 // ...
23 });
24 
25 // Executed when a test database is created...
26 ParallelTesting::setUpTestDatabase(function (string $database, int $token) {
27 Artisan::call('db:seed');
28 });
29 
30 ParallelTesting::tearDownTestCase(function (int $token, TestCase $testCase) {
31 // ...
32 });
33 
34 ParallelTesting::tearDownProcess(function (int $token) {
35 // ...
36 });
37 }
38}

获取并行测试标识符(Token)

如果你想在应用程序测试代码的其他任何位置访问当前的并行进程“标识符”,可以使用 token 方法。该标识符是一个用于区分单个测试进程的唯一字符串,可用于在并行测试进程之间划分资源。例如,Laravel 会自动将此标识符追加到每个并行测试进程创建的测试数据库名称末尾。

1$token = ParallelTesting::token();

报告测试覆盖率

此功能需要 XdebugPCOV

在运行应用程序测试时,你可能需要确定测试用例是否确实覆盖了应用程序代码,以及运行测试时使用了多少应用程序代码。为此,你可以在调用 test 命令时提供 --coverage 选项。

1php artisan test --coverage

强制执行最小覆盖率阈值

你可以使用 --min 选项为应用程序定义最低测试覆盖率阈值。如果未达到此阈值,测试套件将失败。

1php artisan test --coverage --min=80.3

测试性能分析

Artisan 测试运行器还包含一个方便的机制来列出应用程序中最慢的测试。使用 --profile 选项调用 test 命令,它将展示最慢的十个测试列表,让你轻松排查哪些测试可以优化,从而加快测试套件的运行速度。

1php artisan test --profile

配置缓存

运行测试时,Laravel 会为每个独立的测试方法启动应用程序。如果没有缓存的配置文件,应用程序中的每个配置文件都必须在测试开始时加载。要构建一次配置并在单次运行的所有测试中重用它,你可以使用 Illuminate\Foundation\Testing\WithCachedConfig trait。

1<?php
2 
3use Illuminate\Foundation\Testing\WithCachedConfig;
4 
5pest()->use(WithCachedConfig::class);
6 
7// ...
1<?php
2 
3namespace Tests\Feature;
4 
5use Illuminate\Foundation\Testing\WithCachedConfig;
6use Tests\TestCase;
7 
8class ConfigTest extends TestCase
9{
10 use WithCachedConfig;
11 
12 // ...
13}