Laravel中AuthenticatedSessionControllerTest登录登出测试批量运行报404
问题
在Laravel应用中测试登录和登出功能时遇到问题:运行测试套件时部分测试返回404状态码(而非预期的401或200),但单独运行每个测试却完全正常。测试代码如下:
class AuthenticatedSessionControllerTest extends TestCase { use RefreshDatabase; public function test_user_can_login_with_valid_credentials() { $user = User::factory()->create([ 'email' => 'test@example.com', 'password' => bcrypt('password123'), ]); $response = $this->postJson('/api/v1/login', [ 'email' => 'test@example.com', 'password' => 'password123', ]); $response->assertStatus(200) ->assertJsonStructure([ 'success', 'accessToken', 'token_type', 'message', 'data' => ['id', 'name', 'email'], 'roles', 'permissions', ]); } public function test_user_cannot_login_with_invalid_credentials() { $response = $this->postJson('/api/v1/login', [ 'email' => 'test@example.com', 'password' => 'wrongpassword', ]); $response->assertStatus(200) ->assertJson([ 'success' => false, 'message' => 'These credentials do not match our records', ]); } public function test_user_can_logout() { $user = User::factory()->create([ 'email' => 'test@example.com', 'password' => bcrypt('password123'), ]); Sanctum::actingAs($user); $response = $this->postJson('/api/v1/login', [ 'email' => 'test@example.com', 'password' => 'password123', ]); $response = $this->postJson('/api/v1/logout'); $response->assertStatus(200) ->assertJson([ 'success' => true, 'message' => 'Successfully logged out', ]); $this->assertCount(0, $user->tokens); } }
请问是什么原因导致这些测试仅在批量运行时失败报404?是否在Laravel或Sanctum的状态处理上有遗漏?
解决方案
导致批量运行测试时出现404、单独运行正常的核心原因是测试间的状态污染或路由加载异常,以下是具体排查和修复步骤:
1. 清除测试环境的路由缓存
如果测试环境下意外缓存了路由,会导致新增/修改的路由无法被识别,出现404。执行以下命令清除测试环境的路由缓存:
php artisan route:clear --env=testing
同时确保.env.testing中使用内存缓存,避免状态残留:
CACHE_DRIVER=array
2. 移除测试中冗余的认证操作
你的test_user_can_logout方法中同时使用了Sanctum::actingAs($user)和手动登录接口,这会导致认证状态混乱,干扰中间件判断。修改后:
public function test_user_can_logout() { $user = User::factory()->create([ 'email' => 'test@example.com', 'password' => bcrypt('password123'), ]); // 直接用Sanctum模拟已认证状态,无需重复调用登录接口 Sanctum::actingAs($user); $response = $this->postJson('/api/v1/logout'); $response->assertStatus(200) ->assertJson([ 'success' => true, 'message' => 'Successfully logged out', ]); $this->assertCount(0, $user->tokens); }
3. 强制重置测试间的应用状态
在测试类的setUp方法中强制刷新应用实例,确保每个测试都使用干净的环境:
protected function setUp(): void { parent::setUp(); $this->refreshApplication(); // 重置应用和路由状态 }
4. 验证路由注册的正确性
检查routes/api.php,确保目标路由被正确注册,且没有被错误的条件判断包裹:
// routes/api.php Route::prefix('v1')->group(function () { Route::post('/login', [AuthenticatedSessionController::class, 'login']); Route::middleware('auth:sanctum')->post('/logout', [AuthenticatedSessionController::class, 'logout']); });
5. 检查测试类的初始化逻辑
确保测试类继承的TestCase没有遗漏父类的setUp/tearDown调用,否则会导致应用实例无法正确重置:
// 正确的初始化示例 protected function setUp(): void { parent::setUp(); // 自定义初始化逻辑(如果有) }
内容的提问来源于stack exchange,提问作者Abdulrahman Astra
相关产品推荐
相关产品推荐

