简介
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
{
// 该测试使用了 Laravel 的测试功能……
}
#[UnitTest]
public function test_get_state_returns_state_from_abbreviation(): void
{
// 该测试运行时不会启动应用……
}
} 可通过存根发布功能自定义测试存根。
测试生成后,可按照常规方式使用 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
{
/**
* 基础测试示例。
*/
public function test_basic_test(): void
{
$this->assertTrue(true);
}
} 如果在测试类中自定义了 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=4 并行运行测试时,部分 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 门面,可指定在进程或测试用例的 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
{
/**
* 引导应用服务。
*/
public function boot(): void
{
ParallelTesting::setUpProcess(function (int $token) {
// ...
});
ParallelTesting::setUpTestCase(function (int $token, TestCase $testCase) {
// ...
});
// 创建测试数据库时执行……
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 特性:
<?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;
// ...
}