package app import ( "fmt" . "code.hoteas.com/golang/hotime" . "code.hoteas.com/golang/hotime/common" ) var ExpectDemoTest = CtrTest{ // ─── 基础类型结构校验 + Verify 值断言 ────────────────── "string_result": {Desc: "返回字符串-结构+值校验", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetString("result") if result != "操作成功" { return fmt.Errorf("result 期望 '操作成功', 实际 '%s'", result) } return nil }).Get("result是字符串", 0, "样本") }}, "number_result": {Desc: "返回整数-结构+值校验", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetCeilInt64("result") if result != 42 { return fmt.Errorf("result 期望 42, 实际 %d", result) } return nil }).Get("result是整数", 0, int64(1)) }}, "float_result": {Desc: "返回小数-结构+值校验", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetFloat64("result") if result != 3.14 { return fmt.Errorf("result 期望 3.14, 实际 %f", result) } return nil }).Get("result是小数", 0, float64(1.0)) }}, "bool_result": {Desc: "返回布尔-结构+值校验", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetBool("result") if !result { return fmt.Errorf("result 期望 true, 实际 false") } return nil }).Get("result是布尔", 0, true) }}, "map_result": {Desc: "返回对象-结构+值校验", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetMap("result") if result == nil { return fmt.Errorf("result 为 nil") } if result.GetCeilInt64("id") != 1 { return fmt.Errorf("id 期望 1, 实际 %d", result.GetCeilInt64("id")) } if result.GetString("name") != "示例商品" { return fmt.Errorf("name 期望 '示例商品', 实际 '%s'", result.GetString("name")) } if !result.GetBool("in_stock") { return fmt.Errorf("in_stock 期望 true") } return nil }).Get("result是Map-校验字段名+类型+值", 0, Map{ "id": int64(1), "name": "sample", "price": float64(1.0), "in_stock": true, }) }}, "nested_result": {Desc: "返回嵌套对象-结构+值校验", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetMap("result") if result == nil { return fmt.Errorf("result 为 nil") } if result.GetCeilInt64("id") != 100 { return fmt.Errorf("id 期望 100, 实际 %d", result.GetCeilInt64("id")) } if result.GetString("title") != "测试订单" { return fmt.Errorf("title 期望 '测试订单', 实际 '%s'", result.GetString("title")) } customer := result.GetMap("customer") if customer == nil { return fmt.Errorf("customer 为 nil") } if customer.GetString("name") != "张三" { return fmt.Errorf("customer.name 期望 '张三', 实际 '%s'", customer.GetString("name")) } if customer.GetString("phone") != "13800138000" { return fmt.Errorf("customer.phone 期望 '13800138000', 实际 '%s'", customer.GetString("phone")) } items := result.GetSlice("items") if len(items) != 2 { return fmt.Errorf("items 期望 2 条, 实际 %d 条", len(items)) } firstItem := items.GetMap(0) if firstItem.GetString("goods_name") != "苹果" { return fmt.Errorf("items[0].goods_name 期望 '苹果', 实际 '%s'", firstItem.GetString("goods_name")) } delivery := result.GetMap("extra").GetMap("delivery") if delivery == nil { return fmt.Errorf("extra.delivery 为 nil") } if delivery.GetString("address") != "XX路1号" { return fmt.Errorf("extra.delivery.address 期望 'XX路1号', 实际 '%s'", delivery.GetString("address")) } return nil }).Get("深层嵌套Map+Slice+Map", 0, Map{ "id": int64(1), "title": "sample", "customer": Map{"id": int64(1), "name": "sample", "phone": "sample"}, "items": Slice{Map{ "id": int64(1), "goods_name": "sample", "quantity": int64(1), "price": float64(1.0), }}, "extra": Map{ "delivery": Map{"address": "sample", "fee": int64(1)}, }, }) }}, "slice_result": {Desc: "返回数组-结构+值校验", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetSlice("result") if len(result) != 2 { return fmt.Errorf("result 期望 2 条, 实际 %d 条", len(result)) } first := result.GetMap(0) if first.GetString("name") != "标签A" { return fmt.Errorf("result[0].name 期望 '标签A', 实际 '%s'", first.GetString("name")) } second := result.GetMap(1) if second.GetString("name") != "标签B" { return fmt.Errorf("result[1].name 期望 '标签B', 实际 '%s'", second.GetString("name")) } return nil }).Get("result直接是Slice", 0, Slice{Map{"id": int64(1), "name": "sample"}}) }}, // ─── 错误先行 + 正确请求完整范式 ───────────────────── "error_demo": {Desc: "错误先行+正确请求完整校验", Func: func(a *Api) { // ======== 第一步:错误用例(先行) ======== 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 值断言 ======== a.Form(Map{"name": "测试商品"}). Verify(func(a *Api) error { result := a.Resp().GetBody().GetMap("result") if result == nil { return fmt.Errorf("result 为 nil") } if result.GetCeilInt64("id") != 1 { return fmt.Errorf("id 期望 1, 实际 %d", result.GetCeilInt64("id")) } if result.GetString("name") != "测试商品" { return fmt.Errorf("name 期望 '测试商品', 实际 '%s'", result.GetString("name")) } if !result.GetBool("created") { return fmt.Errorf("created 期望 true") } return nil }). Post("名称正确-结构+值校验", 0, Map{ "id": int64(1), "name": "sample", "created": true, }) }}, "no_expect": {Desc: "最小正确用例-仍需值断言", Func: func(a *Api) { a.Verify(func(a *Api) error { result := a.Resp().GetBody().GetMap("result") if result == nil { return fmt.Errorf("result 为 nil") } if result.GetCeilInt64("id") != 1 { return fmt.Errorf("id 期望 1, 实际 %d", result.GetCeilInt64("id")) } if result.GetString("data") != "无预期校验" { return fmt.Errorf("data 期望 '无预期校验', 实际 '%s'", result.GetString("data")) } return nil }).Get("有Verify值断言", 0, Map{"id": int64(1), "data": "sample"}) }}, // ─── Verify 完整范式:错误 → 数据准备 → 正确请求 + 响应断言 + DB 校验 ─ "verify_demo": {Desc: "Verify完整范式演示", Func: func(a *Api) { // ======== 第一步:错误用例 ======== a.Form(Map{"name": ""}).Post("名称为空", 3, "名称不能为空") // ======== 第二步:准备测试数据 ======== // 先插入一条已有记录,用于后续 DB 校验时确认"新增"行为 a.DB().Insert("test_batch", Map{ "name": "existing_record", "title": "verify_demo", "state": 1, }) // ======== 第三步:正确请求 + Verify 统一校验 ======== name := "verify_test" a.Form(Map{"name": name}). Verify(func(a *Api) error { // 响应值断言 result := a.Resp().GetBody().GetMap("result") if result == nil { return fmt.Errorf("result 为 nil") } if result.GetCeilInt64("id") <= 0 { return fmt.Errorf("返回的 id 必须大于 0, 实际 %d", result.GetCeilInt64("id")) } if result.GetString("name") != name { return fmt.Errorf("name 期望 '%s', 实际 '%s'", name, result.GetString("name")) } // 数据库状态校验 row := a.DB().Get("test_batch", "*", Map{"AND": Map{"name": name, "title": "verify_demo"}}) if row == nil { return fmt.Errorf("test_batch 表未找到 name=%s 的记录", name) } if row.GetCeilInt64("state") != 0 { return fmt.Errorf("test_batch.state 期望 0, 实际 %d", row.GetCeilInt64("state")) } // 校验之前插入的记录仍然存在(验证不会误删) existing := a.DB().Get("test_batch", "*", Map{"AND": Map{"name": "existing_record", "title": "verify_demo"}}) if existing == nil { return fmt.Errorf("之前插入的 existing_record 丢失") } return nil }). Post("写入并校验DB+响应", 0, Map{"id": int64(1), "name": "sample"}) // Verify 返回 error 会使该用例失败并写入 failReason(见覆盖率报告「未通过的接口」) }}, }