Laravel9单元测试断言200失败,返回302重定向问题排查
Laravel路由单元测试:正确测试返回
back()重定向的场景 测试用例test_client_save_access_if_authorised执行时,assertStatus(200)断言失败,实际返回302状态码。确认控制器逻辑已正常执行且数据保存成功,问题源于控制器返回back()生成重定向响应,以下是正确的测试方案:
原测试代码
public function test_client_save_access_if_authorised() { $this->seed(TestSeederBase::class); $user = User::find(1); $response = $this->actingAs($user, 'web') ->withSession(['banned' => false]) ->post('/client/save', [ 'csrf_token' => csrf_token(), 'id' => 1, 'title' => 'Test Title', 'contact_1_title' => 'Another Title', 'contact_1_email' => 'cas@example.com', 'contact_1_phone_number' => '01234567890', ]); $response->dumpHeaders(); $response->dumpSession(); $response->dump(); $response->assertStatus(200); $task = JobWorkItem::where('job_number', 1) ->where('user_id', 1) ->first(); $this->assertSame(1, $task->job_number); }
对应控制器代码
/** * @param ClientRequest $request * @return \Illuminate\Http\RedirectResponse */ public function store( ClientRequest $request ) { $is_enabled = 0; if (isset($request->is_enabled) && $request->is_enabled === 'on') { $is_enabled = 1; } $client = Client::find($request->id); $client->is_enabled = $is_enabled; $client->title = $request->title; $client->save(); // 更新联系人数据 $all = ClientContact::where('client_id', $request->id)->get(); foreach ($all as $cc) { if (isset($request->{'contact_' . $cc->id . '_title'})) { $title = $request->{'contact_' . $cc->id . '_title'}; $email = $request->{'contact_' . $cc->id . '_email'}; $phone = $request->{'contact_' . $cc->id . '_phone_number'}; if ($title === '-' || $title === '') { $cc->forceDelete(); } else { $cc->title = $title; $cc->email = $email; $cc->phone_number = $phone; $cc->save(); } } } return back(); }
问题核心
控制器返回的back()会生成302重定向响应,而非200状态码的页面响应,因此原断言assertStatus(200)必然失败。同时back()依赖请求的HTTP_REFERER头,测试环境中若未设置,Laravel会默认重定向到APP_URL对应的地址。
正确测试方案
1. 调整响应断言逻辑
将状态码断言改为验证重定向,同时可指定重定向目标:
- 用
assertStatus(302)验证重定向状态码 - 用
assertRedirectBack()或assertRedirect($url)验证重定向目标
2. 强化业务逻辑验证
测试的核心是确认数据是否正确更新,而非仅验证响应状态。
3. 移除冗余参数
Laravel测试框架会自动处理CSRF令牌,无需手动在请求中传入csrf_token()参数。
修改后的测试代码示例
public function test_client_save_access_if_authorised() { $this->seed(TestSeederBase::class); $user = User::find(1); // 设置referer头,模拟从编辑页面发起请求 $response = $this->actingAs($user, 'web') ->withSession(['banned' => false]) ->withHeaders(['HTTP_REFERER' => '/client/edit/1']) ->post('/client/save', [ 'id' => 1, 'title' => 'Test Title', 'contact_1_title' => 'Another Title', 'contact_1_email' => 'cas@example.com', 'contact_1_phone_number' => '01234567890', ]); // 断言重定向状态码 $response->assertStatus(302); // 断言重定向到指定来源地址 $response->assertRedirect('/client/edit/1'); // 或使用专门的back()断言方法 // $response->assertRedirectBack(); // 验证客户端数据更新 $client = Client::find(1); $this->assertEquals('Test Title', $client->title); $this->assertEquals(0, $client->is_enabled); // 验证联系人数据更新 $contact = ClientContact::find(1); $this->assertEquals('Another Title', $contact->title); $this->assertEquals('cas@example.com', $contact->email); $this->assertEquals('01234567890', $contact->phone_number); // 保留原有JobWorkItem相关断言(若与测试逻辑相关) $task = JobWorkItem::where('job_number', 1) ->where('user_id', 1) ->first(); $this->assertNotNull($task); $this->assertSame(1, $task->job_number); }
内容的提问来源于stack exchange,提问作者ThurstonLevi
相关产品推荐
相关产品推荐

