中间件测试应作为普通PHP类进行单元测试,聚焦输入请求→执行逻辑→输出响应链路,使用Request::create构造轻量请求、mock $next闭包,断言返回值;真实请求拦截验证则属Feature测试范畴。

中间件本身不适合用纯单元测试(Unit Test)验证,因为它天然依赖请求-响应生命周期。真正该测的是它的逻辑行为,而不是“它有没有被注册到路由上”——那属于功能测试范畴。所以写中间件测试,核心是:把它当作一个普通 PHP 类来测,剥离框架上下文,只关注 输入请求 → 执行逻辑 → 输出响应/重定向/异常 这一链路是否符合预期。
把中间件当普通类来测,不走 HTTP 流程
中间件的 handle 方法接收 $request、$next 和可选 $parameter,返回 $next($request) 或直接返回响应。测试时无需启动 Laravel 应用或模拟完整请求对象,只需传入一个轻量的 Request 实例(比如用 Illuminate\Http\Request::create),再 mock $next 闭包即可。
- 用
Request::create('/test', 'GET')构造请求,避免依赖真实路由 - 用
$next = function ($req) { return response('ok'); };模拟下游调用 - 实例化中间件后调用
handle(),断言返回值类型或内容 - 例如:测试权限中间件对非管理员返回 403,就 assert 一个
Response实例且 status 是 403
需要测真实请求拦截?改用 Feature 测试 + WithoutMiddleware
如果你关心“这个中间件在真实请求中是否生效”,比如验证登录态校验、CSRF 拦截、IP 白名单等,那就不是单元测试的任务,而是 Feature 测试的事。这时应:
- 在
tests/Feature下建测试类,继承Tests\TestCase - 顶部加
use WithoutMiddleware;(跳过其他中间件干扰),或仅禁用VerifyCsrfToken等特定中间件 - 用
$this->get('/admin/dashboard')发起请求,然后->assertStatus(403)或->assertRedirect('/login') - 若要测带参数的中间件(如
role:admin),确保路由正确绑定:Route::get('/admin')->middleware('role:admin')
怎么测中间件里调用的服务或外部逻辑
中间件常依赖 Auth、Session、Gate、自定义服务等。单元测试时应把这些依赖全部 mock 掉,保持测试纯粹:
- 用
$this->mock(Auth::class)或Mockery::mock(Gate::class)替换门面行为 - 若中间件构造函数注入了服务,创建测试实例时传入 mock 对象:
new RoleCheckMiddleware($mockGate) - 避免在测试中调用
Auth::user()或session()->get()—— 它们会触发真实应用状态,破坏隔离性 - 重点验证:给定某个用户角色 + 某个请求,中间件是否按规则放行或拒绝
别踩这些坑
很多中间件测试失败,不是逻辑问题,而是环境配置或方法误用:
- 在 Unit 测试里用
$this->get()或actingAs()→ 这些方法只在 Feature 测试中可用,Unit 测试会报错 - 测试类放在
tests/Unit却继承Illuminate\Foundation\Testing\TestCase→ 太重,且部分辅助方法(如 database helpers)无意义 - 试图在单元测试中 assert 数据库变更(如日志写入)→ 中间件不该负责持久化,那是服务层或监听器的事
- 没清理 mock 状态,导致多个测试间污染 → 每个 test 方法末尾加
Mockery::close()或用tearDown()
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











