feat(testing): 新增 AnyMsg 方法以跳过错误消息断言

- 在 Api 和 ApiCase 中新增 AnyMsg 方法,允许在状态不为 0 时跳过错误消息的断言,适用于动态内容的用例。
- 更新文档说明,介绍 AnyMsg 的用法及其链式调用示例。
- 在示例测试中添加 AnyMsg 的使用案例,展示其在处理动态错误消息时的便利性。
This commit is contained in:
2026-07-22 04:38:38 +08:00
parent f53d406110
commit ec9d25fef6
3 changed files with 21 additions and 1 deletions
+2
View File
@@ -487,6 +487,8 @@ a.WithSession(Map{"admin_id": int64(1)}).
**省略错误消息(第三参数)**`a.Post("请先登录", 2)` — 当 `status != 0` 且未传第三参数时,框架自动用 `desc`(第一参数)作为期望的错误消息。适合 desc 与实际 msg 完全一致的场景。 **省略错误消息(第三参数)**`a.Post("请先登录", 2)` — 当 `status != 0` 且未传第三参数时,框架自动用 `desc`(第一参数)作为期望的错误消息。适合 desc 与实际 msg 完全一致的场景。
**跳过错误消息断言(AnyMsg**`a.AnyMsg().Post("无效授权码", 1)` — 当 `status != 0` 但错误 msg 含动态内容(网络拨号错误、第三方 API 回传文案等)无法全等断言时,用 `AnyMsg()` 仅断言 status、跳过 msg 校验(同时也不再用 desc 兜底匹配)。`Api``ApiCase` 均可链式调用,如 `a.JSON(...).AnyMsg().Post(...)`。样例见 `example/app/expect_demo_test.go``error_demo`
**省略 result 结构校验(expect**`a.Post("创建成功", 0)` — 仅断言 `status=0`,不校验 result 的内容和结构。适合无需关注返回结构的场景,也适用于非 JSON 响应(二进制文件、纯文本等),此时在 Verify 中通过 `GetRawBody()` 做内容校验。 **省略 result 结构校验(expect**`a.Post("创建成功", 0)` — 仅断言 `status=0`,不校验 result 的内容和结构。适合无需关注返回结构的场景,也适用于非 JSON 响应(二进制文件、纯文本等),此时在 Verify 中通过 `GetRawBody()` 做内容校验。
**省略 Verify**:不设置 Verify 回调时,不会执行响应值断言和数据库状态校验。适合纯查询、无副作用的接口。 **省略 Verify**:不设置 Verify 回调时,不会执行响应值断言和数据库状态校验。适合纯查询、无副作用的接口。
+4
View File
@@ -146,6 +146,10 @@ var ExpectDemoTest = CtrTest{
// ======== 第一步:错误用例(先行) ======== // ======== 第一步:错误用例(先行) ========
a.Form(Map{"name": ""}).Post("名称为空-缺少必填字段", 3, "名称不能为空") a.Form(Map{"name": ""}).Post("名称为空-缺少必填字段", 3, "名称不能为空")
// AnyMsg:跳过错误 msg 断言(仅断言 status)。用于响应 msg 含网络错误等
// 动态内容的用例——desc 与实际 msg 不一致时,无 AnyMsg 会因 desc 兜底匹配而失败
a.Form(Map{"name": ""}).AnyMsg().Post("AnyMsg跳过msg断言-desc与实际msg不一致", 3)
// ======== 第二步:正确请求 + 结构校验 + Verify 值断言 ======== // ======== 第二步:正确请求 + 结构校验 + Verify 值断言 ========
a.Form(Map{"name": "测试商品"}). a.Form(Map{"name": "测试商品"}).
Verify(func(a *Api) error { Verify(func(a *Api) error {
+15 -1
View File
@@ -189,6 +189,13 @@ func (a *Api) Note(note string) *ApiCase {
return c return c
} }
// AnyMsg 跳过错误 msg 断言(仅断言 status),用于响应 msg 含网络错误等动态内容的用例
func (a *Api) AnyMsg() *ApiCase {
c := a.newCase()
c.skipMsg = true
return c
}
// DB 获取数据库实例(在测试事务内) // DB 获取数据库实例(在测试事务内)
func (a *Api) DB() *HoTimeDB { func (a *Api) DB() *HoTimeDB {
return &a.app.Db return &a.app.Db
@@ -221,6 +228,7 @@ type ApiCase struct {
note string note string
verifyFn func(a *Api) error verifyFn func(a *Api) error
bindCase string // 绑定的单接口验收用例名(FromCase) bindCase string // 绑定的单接口验收用例名(FromCase)
skipMsg bool // AnyMsg:跳过错误 msg 断言(用于网络错误等动态消息)
} }
// FromCase 在已有 ApiCase 上绑定验收用例名(若尚未加载模板则加载) // FromCase 在已有 ApiCase 上绑定验收用例名(若尚未加载模板则加载)
@@ -300,6 +308,12 @@ func (c *ApiCase) Note(note string) *ApiCase {
return c return c
} }
// AnyMsg 跳过错误 msg 断言(仅断言 status),可继续链式
func (c *ApiCase) AnyMsg() *ApiCase {
c.skipMsg = true
return c
}
// Verify 设置请求后的自定义校验函数(如查库验证数据状态) // Verify 设置请求后的自定义校验函数(如查库验证数据状态)
// 函数返回 nil 表示校验通过,返回 error 则用例失败并记录错误原因 // 函数返回 nil 表示校验通过,返回 error 则用例失败并记录错误原因
func (c *ApiCase) Verify(fn func(a *Api) error) *ApiCase { func (c *ApiCase) Verify(fn func(a *Api) error) *ApiCase {
@@ -343,7 +357,7 @@ func (c *ApiCase) execute(method, desc string, expectStatus int, expectArgs ...i
hasExpectResult = true hasExpectResult = true
} }
} }
if expectStatus != 0 && expectMsg == "" { if expectStatus != 0 && expectMsg == "" && !c.skipMsg {
expectMsg = desc expectMsg = desc
} }