本文目录导读:

- 基础 PHPUnit 断言(通用)
- Laravel HTTP 测试断言(最常用,占80%)
- 数据库测试断言(重要)
- 集合与 Eloquent 断言
- 测试异常
- 格式化 / 验证响应
- 最推荐的组合用法(最佳实践)
- 💡 核心记忆技巧
在 Laravel 框架中,测试断言主要分为 PHPUnit 原生断言 和 Laravel 专用的测试响应断言。
以下是最常用且必须掌握的断言方法分类整理:
基础 PHPUnit 断言(通用)
这些是测试数据、逻辑最基础的判断。
| 断言方法 | 用途 | 示例 |
|---|---|---|
assertEquals($expected, $actual) |
判断两个值是否相等(松散比较,类型不严格,推荐用下面的) | $this->assertEquals(3, $result); |
assertSame($expected, $actual) |
判断两个值是否全等(严格类型+值) | $this->assertSame(10, $product->price); |
assertTrue($condition) |
断言条件为 true |
$this->assertTrue($user->isAdmin()); |
assertFalse($condition) |
断言条件为 false |
$this->assertFalse($user->isBanned()); |
assertNull($var) |
断言变量为 null |
$this->assertNull($user->deleted_at); |
assertNotNull($var) |
断言变量不为 null |
$this->assertNotNull($order->paid_at); |
assertCount($expected, $array) |
断言数组或集合的元素个数 | $this->assertCount(5, $users); |
assertEmpty($var) |
断言集合、数组、字符串为空 | $this->assertEmpty($cart->items); |
assertNotEmpty($var) |
断言不为空 | $this->assertNotEmpty($errors); |
assertInstanceOf($class, $obj) |
断言对象属于某个类(常用多态/服务容器) | $this->assertInstanceOf(ReportInterface::class, $service); |
assertArrayHasKey($key, $array) |
断言数组中存在指定键名 | $this->assertArrayHasKey('token', $data); |
assertContains($needle, $haystack) |
断言字符/数组包含指定项 | $this->assertContains('laravel', $str); |
assertDatabaseHas(常用独立) |
断言数据库中有对应记录 | (见下面数据库部分) |
Laravel HTTP 测试断言(最常用,占80%)
这些断言基于 $this->get()、$this->post()、$this->actingAs() 等功能。
状态码与视图
$response = $this->get('/login');
// 状态码
$response->assertStatus(200); // 默认成功
$response->assertOk(); // 等同于 assertStatus(200)
$response->assertRedirect('/home'); // 重定向
$response->assertNotFound(); // 404
$response->assertForbidden(); // 403
$response->assertUnauthorized(); // 401
$response->assertServerError(); // 500
// 视图相关
$response->assertViewIs('auth.login'); // 渲染的视图名称
$response->assertViewHas('user'); // 视图包含某个变量
$response->assertViewHas('users', $expectedUsers); // 视图变量值匹配
JSON / API 测试
$response = $this->postJson('/api/login', ['email' => 'a@b.c']);
$response->assertJson(['status' => 'success']); // 包含部分 JSON(推荐)
$response->assertExactJson(['status' => 'success', 'token' => 'abc']); // 完全一致
$response->assertJsonPath('data.user.id', 1); // 定位深层 JSON 路径
$response->assertJsonCount(5, 'data.items'); // JSON 数组元素个数
$response->assertJsonStructure(['data' => ['id', 'name']]); // 结构验证(无需值)
会话与 Cookies(Form 请求)
$response->assertSessionHas('key'); // Session 存在某 key
$response->assertSessionHas('errors'); // 验证失败时,Laravel 自动存 errors
$response->assertSessionHas('errors', 'email'); // errors 中包含 email 字段错误
$response->assertSessionHasNoErrors(); // 无任何验证错误
$response->assertSessionMissing('cart'); // Session 不存在某 key
// 或直接调用 session 助手:
$this->assertSessionHas('status', 'Profile updated!');
认证(Auth)
$user = User::factory()->create();
$this->actingAs($user); // 模拟登录
$response = $this->get('/dashboard');
$response->assertAuthenticated(); // 断言已认证
$this->assertAuthenticatedAs($user); // 断言指定用户
$response->assertGuest(); // 断言是游客(未登录)
数据库测试断言(重要)
测试与数据库交互时使用。
| 断言方法 | 用途 | 示例 |
|---|---|---|
assertDatabaseHas($table, $data) |
数据库表中存在匹配的记录 | $this->assertDatabaseHas('users', ['email' => 'a@b.c']); |
assertDatabaseMissing($table, $data) |
表中不存在匹配记录 | $this->assertDatabaseMissing('orders', ['status' => 'pending']); |
assertSoftDeleted($table, $data) |
确认数据是软删除状态 | $this->assertSoftDeleted('posts', ['id' => 1]); |
assertDatabaseCount($table, $count) |
表中记录总条数 | $this->assertDatabaseCount('users', 10); |
assertModelExists($model) |
模型在数据库中真实存在 | $this->assertModelExists($product); |
assertModelMissing($model) |
模型在数据库中不存在 | $this->assertModelMissing($product); |
集合与 Eloquent 断言
处理集合数据时的常用断言。
use Illuminate\Support\Collection;
$users = collect([...]);
$this->assertCount(3, $users);
$this->assertTrue($users->contains('name', 'John'));
$this->assertFalse($users->isEmpty());
测试异常
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('无效参数');
$this->expectExceptionCode(400);
// 或者直接用 try/catch
格式化 / 验证响应
// 断言响应头
$response->assertHeader('Content-Type', 'application/json');
// 断言响应内容(配合转义处理)
$response->assertSee('欢迎回来'); // 原始 HTML/JSON 字符串包含
$response->assertDontSee('错误信息');
$response->assertSeeInOrder(['第一', '第二']); // 按顺序出现
// 针对 API 响应格式:
$response->assertSuccessful(); // 2xx 状态码
最推荐的组合用法(最佳实践)
在真实项目中,通常在功能测试中组合使用:
public function test_user_can_login_successfully()
{
$user = User::factory()->create(['password' => bcrypt('secret')]);
// 1. 模拟提交请求
$response = $this->post('/login', [
'email' => $user->email,
'password' => 'secret',
]);
// 2. 断言:重定向到首页
$response->assertRedirect('/home');
// 3. 断言:数据库中用户被标记为已登录(通过会话)
$response->assertSessionHas('login_user_id', $user->id);
// 4. 断言:数据库有登录记录(若用登录日志表)
$this->assertDatabaseHas('login_logs', ['user_id' => $user->id]);
// 5. 断言:没有错误提示
$response->assertSessionHasNoErrors();
}
💡 核心记忆技巧
- 看状态码:
assertOk/assertRedirect/assertNotFound - :
assertSee/assertSessionHas/assertDatabaseHas - 看JSON结构:
assertJsonStructure/assertJsonPath - 看认证:
assertAuthenticated/assertGuest
注意:Laravel 10+ 中使用
assertSessionHas不再直接断言errors对象,而是用assertSessionHasErrors()方法简化掉,记得优先使用assertSessionHasNoErrors()来确保表单校验通过。
如果你在测试过程中遇到“断言失败”但无法定位问题,可以先用 $response->dump() 或 dd($response->json()) 在测试代码里打印响应内容,快速排查。