feat(logging): 增强测试框架的日志记录功能
- 在 GenerateSwagger 方法中添加调试日志记录,记录部分运行检查和现有端点的保留情况 - 更新 Action 方法以支持测试模式下的日志缓冲,确保日志记录的准确性 - 删除不再使用的计划文档,简化项目结构
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
---
|
||||
name: 补充 Note 方法示例
|
||||
overview: 在 Testing_API测试框架.md 的"第二步:编写测试用例"部分补充 Note 方法的使用示例和说明,同步更新 SKILL.md。
|
||||
todos:
|
||||
- id: doc-step2-example
|
||||
content: 文档:在第二步的完整订单示例中加入 Note 调用示范
|
||||
status: completed
|
||||
- id: doc-note-section
|
||||
content: 文档:在用例编写范式中新增 Note 使用说明(典型场景 + 示例 + 何时必须用)
|
||||
status: completed
|
||||
- id: doc-hotimev15-sync
|
||||
content: 同步修改 hotimev1.5 中的 Testing_API测试框架.md
|
||||
status: completed
|
||||
- id: skill-note-guide
|
||||
content: SKILL.md:补充 Note 使用指引和更多场景示例
|
||||
status: completed
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# 补充 Note 方法示例到文档和 Skill
|
||||
|
||||
## 现状分析
|
||||
|
||||
目前 `Note` 方法在文档中的存在情况:
|
||||
|
||||
- [链式 API 参考](d:\work\xbc\docs\Testing_API测试框架.md) 第 474、494 行:仅出现在 API 表格中,一句话描述
|
||||
- [API 速查表](d:\work\xbc\docs\Testing_API测试框架.md) 第 662-668 行:只有一个简短示例(`sign = MD5(...)`)
|
||||
- [SKILL.md](C:\Users\92597.cursor\skills\hotime-tdd-testing\SKILL.md) 第 195-197 行:一行示例
|
||||
|
||||
**缺失**:"第二步:编写测试用例"(第 66-149 行)的完整订单示例中完全没有出现 `Note`,而这是新手学习的第一个入口。
|
||||
|
||||
## 需要修改的内容
|
||||
|
||||
### 1. 文档:第二步示例中加入 Note 使用
|
||||
|
||||
在 [Testing_API测试框架.md](d:\work\xbc\docs\Testing_API测试框架.md) 第 80-148 行的订单创建示例中,在**正确请求**部分加入 `Note` 调用,展示以下几种典型场景:
|
||||
|
||||
- 在正确请求处用 `Note` 说明参数值含义(如 `quantity=3` 是故意的用于校验总价 `29.9*3=89.7`)
|
||||
|
||||
### 2. 文档:用例编写范式中新增 Note 独立小节
|
||||
|
||||
在"用例编写范式"部分(第 219 行之后),在"错误用例"之前或之后,新增一个关于 Note 的说明段落或小节,覆盖以下典型使用场景:
|
||||
|
||||
- **参数值参考**:说明某个参数值的来源或含义,如 `Note("status: 0=待付款, 1=已付款, 2=已发货, 3=已完成")`
|
||||
- **算法说明**:简要描述接口涉及的签名/加密算法,如 `Note("sign = MD5(smsProxyKey+timestamp)")`
|
||||
- **接口/用例说明**:补充 desc 无法涵盖的上下文,如 `Note("需先调用 /api/cart/add 加入购物车")` 或 `Note("此接口支持批量操作,最多100条")`
|
||||
- 在用例编写范式表格中增加 Note 的定位说明
|
||||
|
||||
### 3. 文档:同步更新 hotimev1.5 中的同名文件
|
||||
|
||||
[hotimev1.5/docs/Testing_API测试框架.md](d:\work\hotimev1.5\docs\Testing_API测试框架.md) 需要做相同的修改。
|
||||
|
||||
### 4. Skill 文件:补充 Note 指引
|
||||
|
||||
在 [SKILL.md](C:\Users\92597.cursor\skills\hotime-tdd-testing\SKILL.md) 中:
|
||||
|
||||
- 在 Phase 1 的 1.3 小节之后(或 1.2 和 1.3 之间),新增 Note 的使用指引
|
||||
- 说明何时应该使用 Note(有必要的场景),给出 2-3 个典型示例
|
||||
- 在 API 速查的"备注"部分补充更多场景示例
|
||||
|
||||
## 修改要点
|
||||
|
||||
- Note 不改变测试逻辑,只是给调试控制台和 api-spec.json 添加可读说明
|
||||
- Note 是可选的,但在以下场景**建议必须**使用:
|
||||
- 参数中有枚举值(如 status、type)需要说明各值含义
|
||||
- 涉及签名/加密等算法的接口
|
||||
- 接口有前置依赖或特殊调用顺序
|
||||
- Note 可以放在链式调用的任意位置(`a.Note(...)` 或 `c.Note(...)`)
|
||||
|
||||
@@ -12,6 +12,9 @@ var savepointCounter uint64
|
||||
// 如果 action 返回 true 则提交事务;返回 false 则回滚
|
||||
// 测试模式下(testTx != nil),使用 SAVEPOINT 代替真事务,确保嵌套事务不会绕过外层测试事务
|
||||
func (that *HoTimeDB) Action(action func(db HoTimeDB) (isSuccess bool)) (isSuccess bool) {
|
||||
that.testLogBufMu.Lock()
|
||||
logBuf := that.testLogBuf
|
||||
that.testLogBufMu.Unlock()
|
||||
db := HoTimeDB{
|
||||
DB: that.DB,
|
||||
ContextBase: that.ContextBase,
|
||||
@@ -33,6 +36,7 @@ func (that *HoTimeDB) Action(action func(db HoTimeDB) (isSuccess bool)) (isSucce
|
||||
limitMu: sync.Mutex{},
|
||||
testTx: that.testTx,
|
||||
testMu: that.testMu,
|
||||
testLogBuf: logBuf,
|
||||
}
|
||||
|
||||
if that.testTx != nil {
|
||||
|
||||
@@ -275,6 +275,15 @@ func (that *TestApp) GenerateSwagger(title, version, outputDir string) error {
|
||||
}
|
||||
isPartialRun := visitedPaths > 0 && visitedPaths < totalPaths
|
||||
|
||||
// #region agent log
|
||||
func() {
|
||||
if f, err := os.OpenFile("debug-e1b6ef.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
|
||||
fmt.Fprintf(f, `{"sessionId":"e1b6ef","hypothesisId":"D","message":"partial_run_check","data":{"proj":"%s","totalPaths":%d,"visitedPaths":%d,"isPartialRun":%v}}`+"\n", projName, totalPaths, visitedPaths, isPartialRun)
|
||||
f.Close()
|
||||
}
|
||||
}()
|
||||
// #endregion
|
||||
|
||||
// 仅部分运行时才加载已有 spec 用于合并,全量运行时清空重建
|
||||
var existingEndpoints map[string]map[string]interface{}
|
||||
if isPartialRun {
|
||||
@@ -302,10 +311,40 @@ func (that *TestApp) GenerateSwagger(title, version, outputDir string) error {
|
||||
// 部分运行且该路径未被访问 → 保留已有 spec 中的数据
|
||||
if isPartialRun && !visited[apiPath] {
|
||||
if existing, ok := existingEndpoints[apiPath]; ok {
|
||||
// #region agent log
|
||||
if strings.Contains(apiPath, "batch") {
|
||||
func() {
|
||||
if f, err := os.OpenFile("debug-e1b6ef.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
|
||||
fmt.Fprintf(f, `{"sessionId":"e1b6ef","hypothesisId":"D","message":"kept_existing","data":{"path":"%s"}}`+"\n", apiPath)
|
||||
f.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
// #endregion
|
||||
endpoints = append(endpoints, existing)
|
||||
continue
|
||||
}
|
||||
// #region agent log
|
||||
if strings.Contains(apiPath, "batch") {
|
||||
func() {
|
||||
if f, err := os.OpenFile("debug-e1b6ef.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
|
||||
fmt.Fprintf(f, `{"sessionId":"e1b6ef","hypothesisId":"D","message":"NOT_in_existing_file","data":{"path":"%s"}}`+"\n", apiPath)
|
||||
f.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
// #region agent log
|
||||
if strings.Contains(apiPath, "batch") && isPartialRun && visited[apiPath] {
|
||||
func() {
|
||||
if f, err := os.OpenFile("debug-e1b6ef.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
|
||||
fmt.Fprintf(f, `{"sessionId":"e1b6ef","hypothesisId":"D","message":"regenerated","data":{"path":"%s","numRecs":%d}}`+"\n", apiPath, len(recs))
|
||||
f.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
// #endregion
|
||||
|
||||
httpMethod := "POST"
|
||||
if len(recs) > 0 && recs[0].Method != "" {
|
||||
|
||||
Reference in New Issue
Block a user