laravel路由测试必须走完整http生命周期,常见错误包括404(路由未注册)、419(csrf缺失)、500(中间件异常);应使用$this->get()等方法而非app()->call(),api路由须用json()方法并注意中间件与请求头配置。

测试 Laravel 路由时 get() 和 assertStatus() 为什么总报错?
因为没用对测试上下文——Laravel 的路由测试必须走完整的 HTTP 生命周期,不能直接调用控制器方法。用 get() 等测试方法时,底层会触发中间件、路由匹配、CSRF 验证(如果启用)、模型绑定等全部流程,所以失败往往不是路由写错了,而是环境没配对。
常见错误现象:404 Not Found(路由未注册或命名空间错)、419 Page Expired(CSRF token 缺失)、500 Internal Server Error(中间件抛异常或配置未加载)。
- 测试前确保在
tests/Feature/下,且类继承Tests\TestCase - 所有路由测试必须用
$this->get('/xxx')或$this->post('/xxx'),别用app()->call() - POST/PUT/PATCH 请求需加
withoutMiddleware()或手动传_token,否则 CSRF 中间件会拦截 - 若路由带参数(如
/user/{id}),用$this->get(route('user.show', ['id' => 1]))比硬编码路径更安全
如何让路由测试覆盖重定向、中间件和命名路由?
命名路由和中间件是 Laravel 路由的核心能力,但测试时容易只测“能访问”,漏掉行为逻辑。比如 auth 中间件是否真跳登录页、route('login') 是否返回 302、带 where 约束的路由是否拒绝非法参数。
- 测试重定向:用
$this->get('/admin')->assertRedirect(route('login')),别只断言状态码 - 测试中间件效果:对需要登录的路由,先不登录,再
assertStatus(302);登录后再测assertStatus(200) - 测试命名路由存在性:用
Route::has('profile.edit')在测试 setup 里提前校验,避免拼写错误导致后续全挂 - 测试 where 约束:传非法值如
$this->get('/post/abc'),应得404;合法值如/post/123才进控制器
TestCase::withoutExceptionHandling() 该不该开?
开了能看到完整报错堆栈,关了只能看到模糊的 500,但盲目开启会掩盖真实用户视角——线上用户可看不到异常详情。它只适合定位问题,不该作为常规测试手段。
- 调试阶段可临时加
$this->withoutExceptionHandling()查 Controller 或 Model 报错源头 - CI 环境或正式测试套件中必须关闭,否则可能暴露敏感路径或配置信息
- 更稳妥的方式是用
expectException()显式断言预期异常,比如测试权限失败时抛AuthorizationException - 注意:开启后
assertStatus()可能失效,因为异常未被渲染为响应,建议仅在单个 test 方法内局部启用
测试 API 路由和 Web 路由混用时要注意什么?
Laravel 默认把 api 和 web 路由分组,中间件、Session、CSRF、跨域策略全都不一样。拿 Web 测试方法去测 API 路由,大概率栽在 StartSession 或 VerifyCsrfToken 上。
- API 路由测试一律用
$this->json('GET', '/api/users'),别用$this->get() - Web 路由测试默认带 Session,API 测试默认无 Session —— 别指望
Auth::user()在 API 测试里自动可用 - 若 API 需认证,用
$this->actingAs($user, 'api'),而非withSession() - 检查
routes/api.php是否被RouteServiceProvider正确加载(看mapApiRoutes()是否调用)
路由测试最易被忽略的是「中间件执行顺序」和「请求头环境」——比如测试 JSON 接口却没设 Accept: application/json,Laravel 可能返回 HTML 登录页而不是 JSON 错误;又比如自定义中间件依赖 Request::ip(),但在测试里没 mock,结果永远拿不到预期值。










