测试:入门
简介
Laravel 从设计之初就考虑了测试。事实上,开箱即用支持 Pest 与 PHPUnit 测试,应用中也已配置好 phpunit.xml 文件。框架还提供便捷的辅助方法,让你可以富有表现力地测试应用。
默认情况下,应用的 tests 目录包含两个子目录:Feature 与 Unit。单元测试专注于代码中非常小、相互隔离的部分;实际上,大多数单元测试可能只关注单个方法。「Unit」测试目录中的测试不会启动 Laravel 应用,因此无法访问应用的数据库或其他框架服务。
功能测试可以覆盖更大范围的代码,包括多个对象之间的交互,甚至对 JSON 端点发起完整的 HTTP 请求。一般来说,大多数测试应该是功能测试。这类测试最能让你确信系统整体按预期运行。
Feature 与 Unit 测试目录中都提供了 ExampleTest.php 文件。安装新的 Laravel 应用后,执行 vendor/bin/pest、vendor/bin/phpunit 或 php artisan test 命令即可运行测试。
环境
运行测试时,由于 phpunit.xml 中定义的环境变量,Laravel 会自动将配置环境设为 testing。Laravel 还会自动将会话与缓存配置为 array 驱动,以便测试期间不会持久化任何会话或缓存数据。
你可以根据需要自由定义其他测试环境配置值。testing 环境变量可在应用的 phpunit.xml 中配置,但在运行测试前请务必使用 config:clear Artisan 命令清除配置缓存!
.env.testing 环境文件
此外,你可以在项目根目录创建 .env.testing 文件。运行 Pest、PHPUnit 测试,或以 --env=testing 选项执行 Artisan 命令时,将使用该文件代替 .env。
创建测试
要创建新的测试用例,请使用 make:test Artisan 命令。默认情况下,测试会放在 tests/Feature 目录:
php artisan make:test UserTest若要在 tests/Unit 目录中创建测试,执行 make:test 时可使用 --unit 选项:
php artisan make:test UserTest --unit如果你的测试类大体依赖 Laravel 的测试功能,但某个测试方法不需要启动框架,可为该方法添加 #[UnitTest] 属性,以便仅跳过该测试的应用启动。
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\Attributes\UnitTest;
use Tests\TestCase;
class LocationServiceTest extends TestCase
{
public function test_get_coordinates_resolves_address(): void
{
// This test uses Laravel's testing features...
}
#[UnitTest]
public function test_get_state_returns_state_from_abbreviation(): void
{
// This test runs without booting the application...
}
}INFO
测试桩可通过发布 stub 进行自定义。
测试生成后,可像往常一样使用 Pest 或 PHPUnit 编写测试。要运行测试,请在终端执行 vendor/bin/pest、vendor/bin/phpunit 或 php artisan test 命令:
<?php
test('basic', function () {
expect(true)->toBeTrue();
});<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*/
public function test_basic_test(): void
{
$this->assertTrue(true);
}
}WARNING
若在测试类中自定义 setUp / tearDown 方法,请务必调用父类相应的 parent::setUp() / parent::tearDown()。通常应在自己的 setUp 开头调用 parent::setUp(),在 tearDown 末尾调用 parent::tearDown()。
运行测试
如前所述,写好测试后,可使用 pest 或 phpunit 运行:
./vendor/bin/pest./vendor/bin/phpunit除了 pest 或 phpunit 命令,你还可以使用 test Artisan 命令运行测试。Artisan 测试运行器会提供详细的测试报告,便于开发与调试:
php artisan test任何可传给 pest 或 phpunit 的参数,也可传给 Artisan test 命令:
php artisan test --testsuite=Feature --stop-on-failure并行运行测试
默认情况下,Laravel 与 Pest / PHPUnit 会在单个进程中按顺序执行测试。不过,你可以通过在多个进程中同时运行测试,大幅缩短测试耗时。开始前,请将 brianium/paratest Composer 包安装为「dev」依赖。然后在执行 test Artisan 命令时加上 --parallel 选项:
composer require brianium/paratest --dev
php artisan test --parallel默认情况下,Laravel 会按本机可用 CPU 核心数创建相应数量的进程。你也可以使用 --processes 选项调整进程数:
php artisan test --parallel --processes=4WARNING
并行运行测试时,部分 Pest / PHPUnit 选项(例如 --do-not-cache-result)可能不可用。
并行测试与数据库
只要已配置主数据库连接,Laravel 会自动为每个并行测试进程创建并迁移测试数据库。测试数据库名会带上每个进程唯一的进程令牌后缀。例如,若有两个并行测试进程,Laravel 将创建并使用 your_db_test_1 与 your_db_test_2 测试数据库。
默认情况下,测试数据库会在多次调用 test Artisan 命令之间保留,以便后续 test 调用复用。不过,你可以使用 --recreate-databases 选项重新创建它们:
php artisan test --parallel --recreate-databases并行测试钩子
有时,你可能需要为应用测试所用的某些资源做准备,以便多个测试进程能安全地使用它们。
使用 ParallelTesting facade,你可以指定在进程或测试用例的 setUp 与 tearDown 时执行的代码。给定的闭包会分别收到包含进程令牌与当前测试用例的 $token 和 $testCase 变量:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\ParallelTesting;
use Illuminate\Support\ServiceProvider;
use PHPUnit\Framework\TestCase;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
ParallelTesting::setUpProcess(function (int $token) {
// ...
});
ParallelTesting::setUpTestCase(function (int $token, TestCase $testCase) {
// ...
});
// Executed when a test database is created...
ParallelTesting::setUpTestDatabase(function (string $database, int $token) {
Artisan::call('db:seed');
});
ParallelTesting::tearDownTestCase(function (int $token, TestCase $testCase) {
// ...
});
ParallelTesting::tearDownProcess(function (int $token) {
// ...
});
}
}访问并行测试令牌
若要在应用测试代码的其他位置访问当前并行进程的「令牌」,可使用 token 方法。该令牌是单个测试进程的唯一字符串标识符,可用于在并行测试进程间划分资源。例如,Laravel 会自动将该令牌追加到每个并行测试进程所创建的测试数据库名末尾:
$token = ParallelTesting::token();
报告测试覆盖率
运行应用测试时,你可能想了解测试用例是否真正覆盖了应用代码,以及运行测试时用到了多少应用代码。为此,可在调用 test 命令时提供 --coverage 选项:
php artisan test --coverage强制最低覆盖率阈值
你可以使用 --min 选项为应用定义最低测试覆盖率阈值。未达到该阈值时,测试套件将失败:
php artisan test --coverage --min=80.3分析测试性能
Artisan 测试运行器还提供便捷机制,用于列出应用中最慢的测试。使用 --profile 选项调用 test 命令,即可看到最慢的十个测试列表,方便你排查哪些测试可以优化以加快测试套件:
php artisan test --profile配置缓存
运行测试时,Laravel 会为每个测试方法启动应用。若没有缓存的配置文件,测试开始时必须加载应用中的每个配置文件。若要构建一次配置并在单次运行的所有测试中复用,可使用 Illuminate\Foundation\Testing\WithCachedConfig trait:
<?php
use Illuminate\Foundation\Testing\WithCachedConfig;
pest()->use(WithCachedConfig::class);
// ...<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\WithCachedConfig;
use Tests\TestCase;
class ConfigTest extends TestCase
{
use WithCachedConfig;
// ...
}