You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 22:14:52