httptest.new是唯一可靠起点,必须用它启动内存服务器以直调iris路由分发逻辑;newapp()须返回未run的完整*iris.application实例,严格复现路由注册、依赖注入及beforeactivation流程,避免404或panic。

httptest.New 是唯一可靠起点
别用 curl 或外部工具压测 MVC 接口——Iris 的路由、中间件、参数绑定都在内存中完成,外部请求绕不过测试隔离层。必须用 httptest.New 启动一个无网络、无端口的内存服务器,它直接调用 Iris 内部的路由分发逻辑,性能高且结果真实。
常见错误是误在 newApp() 里调用 app.Run(),导致测试卡死或报 listen tcp :8080: bind: address already in use;另一个是传入的 *testing.T 复用了其他测试的实例,引发并发 panic。
-
httptest.New(t, newApp())中的t必须是当前测试函数的*testing.T -
newApp()必须返回已注册全部路由、中间件、依赖注入的*iris.Application,且未调用Run - 若 MVC 控制器用了
BeforeActivation注册路径,newApp()中必须完整复现该流程,否则/users/{id}这类带参数的路由根本不会被匹配
并发压测前必须解耦全局状态
MVC 控制器若持有包级变量(比如 var userList []User),在并发测试中会互相污染:TestA 添加用户后,TestB 抽奖可能拿到 TestA 的数据,或因切片长度突变直接 panic。
根本解法不是加锁,而是让每个测试拥有独立数据上下文:
- 把共享状态移到控制器结构体字段,如
type UserController struct { Users []User } - 在
newApp()中为每个测试实例注入新切片:app.Register(&UserController{Users: make([]User, 0)}) - 避免使用
app.ConfigureContainer注册单例 service,改用 request-scoped 或 test-scoped 实例
表单/JSON 参数必须严格匹配 handler 实现
Iris 不自动推断参数来源。你用 e.POST("/import").WithJSON(...) 发送 JSON,但 handler 里没写 c.Ctx.ReadJSON(&req),参数就是空的;你用 WithFormField("users", "a,b"),但 handler 里写的是 c.Ctx.FormValue("user"),那就永远取不到值。
压测时最容易暴露这类不一致:
- GET 请求路径参数(如
{id:long})必须与BeforeActivation中声明的类型完全一致,错写成{id}会导致参数始终为零值 - POST 表单提交必须用
WithFormField,且 key 名与c.Ctx.FormValue("key")完全一致 - JSON 提交前确认 handler 是否调用
ReadJSON,并检查 struct tag(如json:"name")是否匹配字段名
中间件和验证器不会自动跳过
用 httptest 压测时,JWT 验证、CSRF 检查、请求限流等中间件照常执行。如果你没在 newApp() 中挂载 mock 中间件,或者没提供合法 token,所有请求都会卡在中间件层,返回 401 或 429。
验证器(如 ctx.ReadJSON 对 struct tag 的校验)也照常触发,不会因为是测试就绕过:
- 若 handler 接收
type UserReq struct { Name string `json:"name" validate:"required"` },压测时发送{"name":""}会直接返回 400,而不是进到业务逻辑 - JWT 中间件需在测试中注入合法 token:
e.POST("/api/users").WithHeader("Authorization", "Bearer "+validToken) - 不要试图“跳过”中间件来压测,那测的不是真实链路;应该 mock 依赖(如 mock JWT 解析函数),保持链路完整
压测的关键不是跑多快,而是每条请求都走通真实路径——从路由匹配、中间件执行、参数解析、业务处理到响应生成,缺一不可。最容易被忽略的是 BeforeActivation 的路径注册和依赖注入顺序,这两点一旦漏掉,压测跑出来的全是 404 或 panic。











