Files
hotime/.cursor/plans/api测试框架完整实现_ce7fcbde.plan.md
T
hoteas bd20af0c89 refactor(db): 增强测试事务支持和保存点管理
- 在 HoTimeDB 中新增测试事务功能,允许在测试模式下使用事务进行操作
- 实现 BeginTestTx 和 RollbackTestTx 方法,支持测试事务的开启和回滚
- 在 Action 方法中集成保存点管理,确保在测试模式下的嵌套事务处理
- 更新 README.md,添加 API 测试框架的相关说明,提升文档完整性
2026-03-14 10:19:57 +08:00

181 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: API测试框架完整实现
overview: 在 hotimev1.5 框架中实现完整的 API 测试基础设施:链式测试 API、事务回滚隔离、覆盖率追踪、Swagger 文档自动生成。
todos:
- id: db-testtx
content: db/db.go:加 testTx 字段 + BeginTestTx/RollbackTestTx 方法
status: completed
- id: db-query
content: db/query.goQuery(行64) 和 Exec(行120) 加 testTx 优先判断
status: completed
- id: db-transaction
content: db/transaction.goAction 加 testTx 传递 + SAVEPOINT 分支
status: completed
- id: testing-helper
content: 新增 testing_helper.goTestApp、NewTestApp、SetupForTest、RunTests(事务隔离)、PrintCoverage
status: completed
- id: testing-api
content: 新增 testing_api.go:注册类型 + Api/ApiCase/ApiResponse 链式 API + TestCollector
status: completed
- id: testing-swagger
content: 新增 testing_swagger.goGenerateSwagger 合并所有项目生成 Swagger
status: completed
- id: xbc-integration
content: xbc 业务层:user.go 加 UserTest、init.go 加 ProjectTest、新增 app_test.go
status: completed
isProject: false
---
# API 测试框架完整实现
## 一、事务回滚隔离(db 层改造)
核心思路:给 `HoTimeDB` 增加 `testTx` 字段,优先级 `testTx > Tx > DB`。测试模式下 `Action()` 用 MySQL `SAVEPOINT` 代替真事务,保证嵌套事务都在外层测试事务内。
### 1. [db/db.go](d:/work/hotimev1.5/db/db.go) -- 加字段 + 方法
```go
// HoTimeDB 结构体新增字段
testTx *sql.Tx // 测试事务:设置后所有操作都在此事务内
// 新增两个方法
func (that *HoTimeDB) BeginTestTx() error
func (that *HoTimeDB) RollbackTestTx() error
```
### 2. [db/query.go](d:/work/hotimev1.5/db/query.go) -- Query(行64) 和 Exec(行120) 各加一个判断
```go
// 原:if that.Tx != nil { ... } else { ... }
// 改:
if that.testTx != nil {
resl, err = that.testTx.Query(query, processedArgs...)
} else if that.Tx != nil {
resl, err = that.Tx.Query(query, processedArgs...)
} else {
resl, err = db.Query(query, processedArgs...)
}
// Exec 同理
```
### 3. [db/transaction.go](d:/work/hotimev1.5/db/transaction.go) -- Action 加 SAVEPOINT 分支
```go
func (that *HoTimeDB) Action(action func(db HoTimeDB) (isSuccess bool)) (isSuccess bool) {
db := HoTimeDB{
// ...现有字段拷贝...
testTx: that.testTx, // 新增:传递 testTx
}
// 新增:测试模式用 SAVEPOINT
if that.testTx != nil {
spName := "sp_" + Md5(ObjToStr(RandX(100000, 999999)))[:8]
_, _ = that.testTx.Exec("SAVEPOINT " + spName)
db.Tx = that.testTx
isSuccess = action(db)
if !isSuccess {
_, _ = that.testTx.Exec("ROLLBACK TO SAVEPOINT " + spName)
} else {
_, _ = that.testTx.Exec("RELEASE SAVEPOINT " + spName)
}
return isSuccess
}
// 以下原有逻辑不变...
}
```
**改动量:** 3 个文件,约 50 行,生产代码零影响(testTx 默认 nil)。
## 二、链式测试 API
### 4. 新增 [testing_helper.go](d:/work/hotimev1.5/testing_helper.go)
- `TestApp` 结构体(包含 `*Application``projs TestProj``collector *TestCollector`
- `NewTestApp(configPath, TestProj, listeners...)` -- 初始化 Application、注册路由,不启动 HTTP 服务
- `SetupForTest(router Router)` -- 复用 `Run()` 的路由初始化逻辑
- `TestRequest(method, path, body) TestResponse` / `TestRequestWithSession(...)` -- 通过 `httptest` 发请求
- `TestResponse` 结构体
- `RunTests(t)` -- 遍历 TestProj,每个方法级别 `BeginTestTx() + defer RollbackTestTx()`
### 5. 新增 [testing_api.go](d:/work/hotimev1.5/testing_api.go)
注册类型:
- `TestProj map[string]TestProjDef`
- `TestProjDef struct { Proj Proj; Tests ProjTest }`
- `ProjTest map[string]CtrTest`
- `CtrTest map[string]ApiTestDef`
- `ApiTestDef struct { Desc string; Func func(a *Api) }`
链式 API
- `Api` -- 起点,提供 `JSON/Query/Form/File/WithSession` 数据设置和 `Get/Post/Put/Delete` 直接终端
- `ApiCase` -- 链式构建器,支持叠加多种数据类型,终端操作 `Get/Post/Put/Delete(desc, status, msg...)`
- `ApiResponse` -- 响应对象,提供 `GetStatus/GetResult/GetMsg/GetBody/Fail`
- 每个终端方法内自动记录 `TestRecord``TestCollector`
### 6. 新增 [testing_swagger.go](d:/work/hotimev1.5/testing_swagger.go)
- `GenerateSwagger(title, version, outputDir)` -- 遍历 TestProj 生成合并的 OpenAPI 3.0 JSON + Swagger UI HTML
- 利用覆盖率数据,未覆盖接口在文档中标注"暂无测试用例"
## 三、覆盖率追踪
集成在 `testing_helper.go` 中:
- `CoverageReport` / `MethodCoverage` / `TestRecord` / `TestCollector` 类型
- `PrintCoverage()` -- 对比 `Proj`(所有路由)和 `ProjTest`(有测试的路由),输出覆盖率报告
- 运行时追踪:每个 `Post/Get/Put/Delete` 终端方法自动收集 `TestRecord`(路径、用例名、通过/失败、耗时)
- 最终输出:总接口数、已覆盖数、覆盖率百分比、每个接口的用例数和通过/失败计数
## 四、业务层接入(xbc 示例)
### 7. 修改 [xbc/app/user.go](d:/work/xbc/app/user.go) -- 末尾添加 `var UserTest = CtrTest{...}`
```go
var UserTest = CtrTest{
"login": {"用户登录", func(a *Api) {
a.JSON(Map{"name": "138", "password": "123456"}).Post("正常登录", 0)
// ...
}},
"create": {"用户注册", func(a *Api) {
phone := "138" + ObjToStr(RandX(10000000, 99999999))
// 不需要 defer 清理,事务自动回滚
a.JSON(Map{"phone": phone, "password": "123456"}).Post("正常注册", 0)
a.JSON(Map{"phone": phone, "password": "123456"}).Post("重复注册", 3, "该手机号已被注册")
}},
}
```
### 8. 修改 [xbc/app/init.go](d:/work/xbc/app/init.go) -- 添加 `var ProjectTest = ProjTest{...}`
### 9. 新增 [xbc/app/app_test.go](d:/work/xbc/app/app_test.go)
```go
func TestMain(m *testing.M) {
testApp = NewTestApp("../config/config.json", TestProj{
"app": {Project, ProjectTest},
})
code := m.Run()
testApp.PrintCoverage()
testApp.GenerateSwagger("小帮菜 API", "2.1.0", testApp.Config.GetString("tpt"))
os.Exit(code)
}
func TestApi(t *testing.T) {
testApp.RunTests(t)
}
```
## 五、文件改动汇总
- **修改** `d:/work/hotimev1.5/db/db.go` -- 加 testTx 字段 + BeginTestTx/RollbackTestTx
- **修改** `d:/work/hotimev1.5/db/query.go` -- Query/Exec 各加 testTx 判断
- **修改** `d:/work/hotimev1.5/db/transaction.go` -- Action 加 SAVEPOINT 分支 + testTx 传递
- **新增** `d:/work/hotimev1.5/testing_helper.go` -- TestApp、RunTests、覆盖率
- **新增** `d:/work/hotimev1.5/testing_api.go` -- 链式 API + TestCollector
- **新增** `d:/work/hotimev1.5/testing_swagger.go` -- Swagger 生成
- **修改** `d:/work/xbc/app/user.go` -- 末尾添加 UserTest
- **修改** `d:/work/xbc/app/init.go` -- 添加 ProjectTest
- **新增** `d:/work/xbc/app/app_test.go` -- 测试入口