测试是确保代码质量和可靠性的关键。Laravel 内置了对 PHPUnit 的强大支持,提供了丰富的辅助方法和断言,让你能够轻松编写单元测试、功能测试和数据库测试。本章将带你从零开始,掌握在 Laravel 中进行测试的核心技能。
Laravel 项目默认已安装 PHPUnit,配置文件为项目根目录下的 phpunit.xml。运行测试前,请确保配置了正确的数据库环境(通常使用 SQLite 内存数据库)。
创建测试数据库的 .env 设置(推荐):
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
运行所有测试:
php artisan test
或者使用 PHPUnit 直接运行:
./vendor/bin/phpunit
使用 Artisan 命令生成测试类:
php artisan make:test UserTest
php artisan make:test UserTest --unit # 生成单元测试(不启动 Laravel 应用)
生成的测试类位于 tests/Feature(功能测试)或 tests/Unit(单元测试)。功能测试会启动完整的 Laravel 应用,适合测试路由、控制器等。
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
class ExampleTest extends TestCase
{
public function test_basic_test()
{
$this->assertTrue(true);
}
}
PHPUnit 提供了丰富的断言,Laravel 还扩展了一些针对数据库、HTTP 的断言。以下列出常用断言:
| 断言方法 | 说明 |
|---|---|
assertTrue($condition) | 断言条件为真 |
assertFalse($condition) | 断言条件为假 |
assertEquals($expected, $actual) | 断言两个值相等 |
assertSame($expected, $actual) | 断言两个值严格相等(类型也相同) |
assertNull($value) | 断言值为 null |
assertNotNull($value) | 断言值不为 null |
assertCount($expectedCount, $haystack) | 断言数组/集合元素数量 |
assertInstanceOf($expected, $actual) | 断言对象为指定类的实例 |
assertThrows(callable $callback, string $exceptionClass) | 断言抛出异常(Laravel 辅助) |
Laravel 提供了数据库测试的便捷方法,可以在测试中使用 RefreshDatabase trait 来重置数据库,避免数据污染。
use Illuminate\Foundation\Testing\RefreshDatabase;
class UserTest extends TestCase
{
use RefreshDatabase;
public function test_user_can_be_created()
{
$user = User::factory()->create([
'email' => 'test@example.com',
]);
$this->assertDatabaseHas('users', [
'email' => 'test@example.com',
]);
}
}
常用数据库断言:
$this->assertDatabaseHas('users', ['email' => 'test@example.com']);
$this->assertDatabaseMissing('users', ['email' => 'notexist@example.com']);
$this->assertDatabaseCount('users', 1);
功能测试可以模拟 HTTP 请求并验证响应。
public function test_user_can_register()
{
$response = $this->post('/register', [
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => 'password',
'password_confirmation' => 'password',
]);
$response->assertStatus(302); // 重定向
$this->assertDatabaseHas('users', ['email' => 'john@example.com']);
}
常用 HTTP 断言:
$response->assertStatus(200);
$response->assertOk();
$response->assertViewIs('welcome'); // 断言视图
$response->assertSee('Hello, World'); // 断言响应包含文本
$response->assertJson(['status' => 'success']); // 断言 JSON 响应
$response->assertRedirect('/home');
使用 Laravel 的 mock() 辅助函数或 PHPUnit 的 Mock 功能,可以模拟依赖,隔离测试。
// 模拟邮件发送
Mail::fake();
// 执行注册逻辑
$response = $this->post('/register', [...]);
// 断言邮件已发送
Mail::assertSent(WelcomeMail::class);
// 模拟外部服务
Http::fake([
'api.example.com/*' => Http::response(['data' => 'mocked'], 200),
]);
Laravel 为常用的服务提供了 fake 方法:Event::fake()、Queue::fake()、Notification::fake() 等。
Laravel 的测试基类(Tests\TestCase)提供了许多实用方法,如:
$this->actingAs($user); // 模拟已认证用户
$this->withoutExceptionHandling(); // 关闭异常处理(便于调试)
$this->seed(); // 填充数据库种子
$this->artisan('cache:clear'); // 执行 Artisan 命令
模型工厂(database/factories)可以快速生成测试数据。
// 创建单个用户
$user = User::factory()->create();
// 创建多个
$users = User::factory()->count(5)->create();
// 定义关联
$user = User::factory()
->has(Post::factory()->count(3))
->create();
test_user_cannot_register_with_invalid_email。Http::fake() 或模拟对象。php artisan test --coverage 可生成代码覆盖率报告(需安装 pcov 或 xdebug)。
Laravel 与 PHPUnit 的完美结合,让你能够轻松编写高质量的测试用例。从简单的单元测试到复杂的 HTTP 测试和数据库测试,Laravel 提供了丰富的工具和便捷的 API。养成编写测试的习惯,将使你的代码更加健壮,维护成本大幅降低。