中间件未生效主因是未正确注册到路由。需用route:list确认注册、区分路由/控制器注册差异、闭包路由须用route::get()->middleware()、测试应走完整http内核并验证行为而非mock中间件。

测试中间件是否在路由上正确注册
中间件没生效,八成是它根本没挂到路由上。Laravel 的 Route::middleware() 和控制器构造函数里用 middleware() 注册方式行为不同,后者只对控制器方法生效,且不经过路由匹配阶段的中间件栈。
- 用
php artisan route:list --name=your-route-name查看该路由的Middleware列,确认中间件名(如auth、throttle:api)是否出现 - 检查是否误用了
->middleware(['foo'])在闭包路由后——闭包路由不支持链式调用中间件,得写成Route::get(...)->middleware(...) - 若用
Route::group(['middleware' => [...]]),注意子路由是否被意外放在 group 外,导致漏掉
用 PHPUnit 模拟请求验证中间件逻辑
别在浏览器里点来点去测中间件,直接写测试断言它的行为:跳转、拦截、修改请求或响应。关键是让测试走通整个 HTTP 内核,而不是绕过它。
- 用
$this->get('/protected')或$this->post(...)发起真实请求,Laravel 测试工具会自动加载中间件栈 - 如果中间件抛出异常(如
AuthenticationException),测试会失败;想验证这个行为,得用$this->expectException(...)包裹请求 - 避免在测试中 mock 中间件类本身——你测的是“它是否被调用”,不是“它内部怎么写”;mock 会让测试脱离真实执行路径
中间件里依赖容器绑定时的测试陷阱
很多中间件会从容器解析服务,比如 $this->auth = app('auth') 或构造函数注入 Guard $guard。测试时若容器没准备好,就会报 Target [Illuminate\Contracts\Auth\Guard] is not instantiable。
- 确保测试类继承
TestCase而非裸写的PHPUnit\Framework\TestCase,否则 Laravel 应用实例和容器不会启动 - 不要在中间件构造函数里做重操作(如查库、发 HTTP 请求),测试时这些会真实执行,拖慢速度还容易失败;把副作用移到
handle()并加条件控制 - 若中间件依赖自定义接口绑定,记得在
tests/TestCase.php的setUp()里提前 bind,例如$this->app->instance(MyService::class, Mockery::mock(MyService::class))
带参数的中间件(如 throttle:60,1)怎么测
带参数的中间件(像 throttle:60,1)本质是字符串解析,测试时不能只看名字是否注册,得验证参数是否真正影响行为——比如限流中间件是否真在第 61 次请求时返回 429。
- 用
$this->withoutExceptionHandling()关掉异常转换,否则ThrottleRequests抛的ThrottleRequestsException会被转成 429 响应,但响应体结构可能变,断言要用assertStatus(429)而非检查异常类 - 测试限流要控制时间:用
Carbon::setTestNow()冻结时间,或在两次请求间用sleep(1)(仅本地开发环境可行) -
throttle中间件默认用文件缓存,测试时可能受其他测试干扰;可在phpunit.xml里为测试环境设CACHE_DRIVER=array,让它不持久化
中间件测试最常卡在「以为跑起来了,其实根本没进 handle」——多看 route:list 输出,再抓一次请求生命周期里的 dd(),比翻十遍文档管用。











