
Laravel 单元测试中出现 401 Unauthorized 错误,通常是因为 API 认证中间件(如 auth:api)在测试环境下未能正确识别已登录用户,根源多为内存数据库未持久化用户、Passport/Sanctum 配置缺失或 actingAs() 使用不当。
laravel 单元测试中出现 401 unauthorized 错误,通常是因为 api 认证中间件(如 `auth:api`)在测试环境下未能正确识别已登录用户,根源多为内存数据库未持久化用户、passport/sanctum 配置缺失或 `actingas()` 使用不当。
在 Laravel 中,actingAs() 方法默认适用于 web 认证守卫(Guard),而你的控制器明确使用了 auth:api 中间件(见 __construct() 中的 $this->middleware(['auth:api', 'auth.admin'])),这意味着测试必须模拟 API 认证上下文,而非 Web 会话。若未正确配置 API 认证驱动(如 Sanctum 或 Passport),或未为测试环境启用对应认证机制,actingAs() 将无法通过 auth:api 校验,导致所有受保护路由返回 401。
✅ 正确做法取决于你使用的 API 认证方案:
1. 若使用 Laravel Sanctum(推荐用于 SPA/API 测试)
确保 phpunit.xml 中已设置 SANCTUM_ENABLED=true,并在 tests/TestCase.php 的 setUp() 中启用 Sanctum:
use Laravel\Sanctum\Sanctum;
protected function setUp(): void
{
parent::setUp();
Sanctum::actingAs(User::factory()->create()); // 自动颁发 Token 并设置 Authorization Header
}
然后重写测试用例,无需手动调用 actingAs()(Sanctum 会自动处理):
public function testDenyNonAdminUserAccess()
{
$user = User::factory()->create(); // 普通用户,非管理员
$author = Author::factory()->create();
$response = $this->withHeaders([
'Accept' => 'application/json',
])->postJson('/api/books', [
'isbn' => '9788328302341',
'title' => 'Clean code',
'description' => 'Lorem ipsum',
'authors' => [$author->id],
]);
$response->assertStatus(403); // ✅ 现在能正确进入授权逻辑
}
2. 若坚持使用 actingAs()(仅适用于 web 守卫)
需显式指定守卫名称,并确保中间件匹配:
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
// ❌ 错误:默认 actingAs 使用 'web' 守卫,但中间件要求 'api' $this->actingAs($user); // ✅ 正确:强制使用 'api' 守卫(前提是 config/auth.php 中 'api' driver 支持 session 或 token) $this->actingAs($user, 'api');
⚠️ 注意:auth:api 默认 driver 是 token(旧版 Laravel)或 sanctum/passport,不支持 session 驱动的 actingAs()。强行指定 'api' 守卫而未配置对应 driver 将静默失败。
3. 关键验证步骤(调试必做)
在测试开头添加断言,确认用户已存入内存数据库且可被查到:
public function testDenyNonAdminUserAccess()
{
// 调试:验证用户是否真实创建并可查询
$user = User::factory()->create(['email' => 'test@example.com']);
$this->assertDatabaseHas('users', ['email' => 'test@example.com']); // ✅ 确保写入 DB
$this->assertNotNull($user->id); // ✅ ID 不为空
// 后续请求...
}
总结与最佳实践
- ? 根本原则:测试中的认证方式必须与中间件声明的守卫(auth:api)完全一致;
- ? 不要混用 web 守卫的 actingAs() 与 auth:api 中间件;
- ✅ 优先使用 Sanctum 并调用 Sanctum::actingAs(),它会自动注入 Bearer Token;
- ? 运行前检查 config/auth.php 中 guards.api.driver 是否为 sanctum(Laravel 9+ 默认)或 passport;
- ? 在 phpunit.xml 中确保环境变量正确(如
和 )。
遵循以上配置,401 错误将消失,测试可准确验证授权逻辑(如 403 Forbidden),而非卡在认证环节。










