enhance(tests): 改进测试用例记录与覆盖率报告

- 在 ApiCase 中添加失败原因记录,提升测试结果的可读性
- 更新 CoverageReport 结构,增加总用例、通过用例和失败用例计数
- 优化 PrintCoverage 方法,支持详细输出未通过接口及其失败原因
- 更新 Swagger 生成逻辑,包含失败原因字段,增强调试信息
- 改进 SQL 错误计数逻辑,确保在测试模式下准确记录 SQL 错误
This commit is contained in:
2026-04-13 06:45:16 +08:00
parent 9a9b9c83ff
commit 3430bdec19
9 changed files with 516 additions and 151 deletions
+98 -29
View File
@@ -31,20 +31,30 @@ type TestResponse struct {
// CoverageReport 覆盖率报告
type CoverageReport struct {
Total int
Covered int
Missing []string
Details []MethodCoverage
Total int
Covered int
Missing []string
Details []MethodCoverage
TotalCases int
PassedCases int
FailedCases int
}
// MethodCoverage 单个接口的覆盖详情
type MethodCoverage struct {
Path string
HasTest bool
CaseCount int
Passed int
Failed int
Duration time.Duration
Path string
HasTest bool
CaseCount int
Passed int
Failed int
Duration time.Duration
FailedCases []FailedCase
}
// FailedCase 失败用例信息
type FailedCase struct {
CaseName string
FailReason string
}
// TestRecord 单条测试记录
@@ -64,6 +74,7 @@ type TestRecord struct {
Note string
ExpectResult interface{}
VerifyError string
FailReason string
}
// TestCollector 线程安全的测试记录收集器
@@ -106,6 +117,7 @@ func NewTestApp(configPath string, projects TestProj, listeners ...func(*Context
os.Stderr = origStderr
devNull.Close()
app.WebConnectLog = nil
app.Log.SetOutput(io.Discard)
for _, lis := range listeners {
@@ -272,6 +284,10 @@ func (that *TestApp) PrintCoverage() CoverageReport {
mc.Passed++
} else {
mc.Failed++
mc.FailedCases = append(mc.FailedCases, FailedCase{
CaseName: r.CaseName,
FailReason: r.FailReason,
})
}
}
}
@@ -280,9 +296,53 @@ func (that *TestApp) PrintCoverage() CoverageReport {
}
}
// 汇总全部用例统计
for _, d := range report.Details {
report.TotalCases += d.CaseCount
report.PassedCases += d.Passed
report.FailedCases += d.Failed
}
ranCount := len(visited)
isPartialRun := ranCount > 0 && ranCount < report.Covered
// 分拣本次运行中通过/失败的接口
var passedDetails, failedDetails []MethodCoverage
for _, d := range report.Details {
if !d.HasTest || d.CaseCount == 0 {
continue
}
if isPartialRun && !visited[d.Path] {
continue
}
if d.Failed > 0 {
failedDetails = append(failedDetails, d)
} else {
passedDetails = append(passedDetails, d)
}
}
// 计算本次运行的用例统计(部分运行时只统计实际运行的接口)
ranInterfaces := len(failedDetails) + len(passedDetails)
var ranTotalCases, ranPassedCases, ranFailedCases int
if isPartialRun {
for _, d := range failedDetails {
ranTotalCases += d.CaseCount
ranPassedCases += d.Passed
ranFailedCases += d.Failed
}
for _, d := range passedDetails {
ranTotalCases += d.CaseCount
ranPassedCases += d.Passed
ranFailedCases += d.Failed
}
} else {
ranTotalCases = report.TotalCases
ranPassedCases = report.PassedCases
ranFailedCases = report.FailedCases
ranInterfaces = len(failedDetails) + len(passedDetails)
}
fmt.Println("\n========== API 测试覆盖率报告 ==========")
if report.Total > 0 {
fmt.Printf("总接口: %d | 已覆盖: %d | 覆盖率: %.1f%%\n",
@@ -292,27 +352,36 @@ func (that *TestApp) PrintCoverage() CoverageReport {
fmt.Println("总接口: 0")
}
if !isPartialRun {
var ranDetails []MethodCoverage
for _, d := range report.Details {
if d.HasTest && d.CaseCount > 0 {
ranDetails = append(ranDetails, d)
if isPartialRun && ranTotalCases > 0 {
passRate := float64(ranPassedCases) / float64(ranTotalCases) * 100
fmt.Printf("本次运行: %d 个接口 | 总用例: %d | 通过: %d | 未通过: %d | 通过率: %.1f%%\n",
ranInterfaces, ranTotalCases, ranPassedCases, ranFailedCases, passRate)
} else if ranTotalCases > 0 {
passRate := float64(ranPassedCases) / float64(ranTotalCases) * 100
fmt.Printf("总用例: %d | 通过: %d | 未通过: %d | 通过率: %.1f%%\n",
ranTotalCases, ranPassedCases, ranFailedCases, passRate)
}
if len(failedDetails) > 0 {
fmt.Printf("\n---------- 未通过的接口 (%d个) ----------\n", len(failedDetails))
for _, d := range failedDetails {
fmt.Printf(" ✗ %s\t%d 用例 (%d 通过, %d 失败) %v\n",
d.Path, d.CaseCount, d.Passed, d.Failed, d.Duration)
for _, fc := range d.FailedCases {
if fc.FailReason != "" {
fmt.Printf(" [失败] %s — %s\n", fc.CaseName, fc.FailReason)
} else {
fmt.Printf(" [失败] %s\n", fc.CaseName)
}
}
}
if len(ranDetails) > 0 {
fmt.Println("\n本次运行:")
for _, d := range ranDetails {
fmt.Printf(" + %s\t%d 用例 (%d 通过, %d 失败) %v\n",
d.Path, d.CaseCount, d.Passed, d.Failed, d.Duration)
}
}
} else {
fmt.Printf("\n本次运行 %d 个接口:\n", ranCount)
for _, d := range report.Details {
if d.HasTest && d.CaseCount > 0 {
fmt.Printf(" + %s\t%d 用例 (%d 通过, %d 失败) %v\n",
d.Path, d.CaseCount, d.Passed, d.Failed, d.Duration)
}
}
if len(passedDetails) > 0 {
fmt.Println("\n---------- 通过的接口 ----------")
for _, d := range passedDetails {
fmt.Printf(" ✓ %s\t%d 用例 (%d 通过, %d 失败) %v\n",
d.Path, d.CaseCount, d.Passed, d.Failed, d.Duration)
}
}