Laravel 9.x自动化测试状态码异常:预期422却返回302
Laravel 9.x自动化测试:预期422却返回302的问题排查
在Laravel 9.x环境下执行自动化测试时,遇到一个问题:测试用例预期接口返回422(HTTP_UNPROCESSABLE_ENTITY)状态码,但实际返回302。测试环境响应错误,但应用正常运行时返回的响应符合预期。
测试代码(CategoryTest.php)
class CategoryTest extends TestCase { use RefreshDatabase; ... public function test_categories_cannot_create_without_payload_should_receive_422() { $response = $this->post(route('categories.store'), []); $response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY); $response->assertJson([ 'message', 'errors', ]); } ... }
全局FormRequest类代码
namespace App\Http\Requests; use Illuminate\Http\Response; use Illuminate\Validation\ValidationException; use Illuminate\Contracts\Validation\Validator; use Illuminate\Http\Exceptions\HttpResponseException; class FormRequest extends \Illuminate\Foundation\Http\FormRequest { protected function failedValidation(Validator $validator) { if ($this->expectsJson()) { throw new HttpResponseException( response()->json([ 'message' => 'Please check the following error(s)', 'errors' => (new ValidationException($validator))->errors(), ], Response::HTTP_UNPROCESSABLE_ENTITY) ); } parent::failedValidation($validator); } }
问题原因
核心问题在于expectsJson()方法的判断逻辑:
- 应用正常运行时,前端请求通常会携带
Accept: application/json请求头,此时expectsJson()返回true,触发自定义的JSON格式错误响应,返回422状态码。 - 测试代码中使用的
post方法默认不会添加Accept: application/json头,导致expectsJson()返回false,执行父类的failedValidation方法——Laravel默认对非JSON请求的验证失败会返回302重定向(重定向到之前的页面),所以测试得到302状态码。
解决方案
有两种方式可以解决这个问题:
方案一:手动添加Accept请求头
在测试的post请求中,明确添加Accept: application/json头,告知后端期望JSON响应:
$response = $this->post(route('categories.store'), [], ['Accept' => 'application/json']);
方案二:使用postJson方法
Laravel提供了postJson方法,该方法会自动设置Accept: application/json请求头,简化测试代码:
$response = $this->postJson(route('categories.store'), []);
修改测试代码后,expectsJson()会返回true,触发自定义的JSON错误响应,测试即可得到预期的422状态码。
内容的提问来源于stack exchange,提问作者Mr.Singh
相关产品推荐
相关产品推荐

