feat(tests): 增强测试框架的 SQL 日志记录与覆盖率报告
- 在 ApiCase 中添加 SQL 日志记录功能,失败时输出日志以便于调试 - 更新 TestApp 以支持测试模式下的 SQL 日志缓冲,成功与失败的测试均可记录日志 - 改进 PrintCoverage 方法,优化覆盖率报告的输出逻辑,支持部分运行的接口显示 - 增加 Note 备注功能,提升测试用例的可读性与文档化效果 - 更新相关文档,详细说明新功能的使用场景与示例
This commit is contained in:
+50
-8
@@ -1,9 +1,12 @@
|
||||
package hotime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -91,8 +94,22 @@ func (c *TestCollector) MarkVisited(path string) {
|
||||
// projects: 项目定义(路由 + 测试)
|
||||
// listeners: 可选的请求拦截器(与 SetConnectListener 相同)
|
||||
func NewTestApp(configPath string, projects TestProj, listeners ...func(*Context) bool) *TestApp {
|
||||
origStdout := os.Stdout
|
||||
origStderr := os.Stderr
|
||||
devNull, _ := os.Open(os.DevNull)
|
||||
os.Stdout = devNull
|
||||
os.Stderr = devNull
|
||||
|
||||
app := Init(configPath)
|
||||
|
||||
os.Stdout = origStdout
|
||||
os.Stderr = origStderr
|
||||
devNull.Close()
|
||||
|
||||
app.Log.SetOutput(io.Discard)
|
||||
origMode := app.Db.Mode
|
||||
app.Db.Mode = 0
|
||||
|
||||
for _, lis := range listeners {
|
||||
app.SetConnectListener(lis)
|
||||
}
|
||||
@@ -107,6 +124,9 @@ func NewTestApp(configPath string, projects TestProj, listeners ...func(*Context
|
||||
app.HoTimeCache.DisableDbCache()
|
||||
}
|
||||
|
||||
app.Db.Mode = origMode
|
||||
app.Log.SetOutput(os.Stderr)
|
||||
|
||||
return &TestApp{
|
||||
Application: app,
|
||||
projs: projects,
|
||||
@@ -193,6 +213,10 @@ func (that *TestApp) RunTests(t *testing.T) {
|
||||
}
|
||||
defer that.Db.RollbackTestTx()
|
||||
|
||||
methodBuf := &bytes.Buffer{}
|
||||
that.Db.SetTestLogBuffer(methodBuf)
|
||||
defer that.Db.SetTestLogBuffer(nil)
|
||||
|
||||
api := &Api{
|
||||
app: that,
|
||||
path: path,
|
||||
@@ -219,6 +243,7 @@ func (that *TestApp) PrintCoverage() CoverageReport {
|
||||
for _, r := range that.collector.Records {
|
||||
pathRecords[r.Path] = append(pathRecords[r.Path], r)
|
||||
}
|
||||
visited := that.collector.Visited
|
||||
that.collector.mu.Unlock()
|
||||
|
||||
for projName, projDef := range that.projs {
|
||||
@@ -258,6 +283,9 @@ func (that *TestApp) PrintCoverage() CoverageReport {
|
||||
}
|
||||
}
|
||||
|
||||
ranCount := len(visited)
|
||||
isPartialRun := ranCount > 0 && ranCount < report.Covered
|
||||
|
||||
fmt.Println("\n========== API 测试覆盖率报告 ==========")
|
||||
if report.Total > 0 {
|
||||
fmt.Printf("总接口: %d | 已覆盖: %d | 覆盖率: %.1f%%\n",
|
||||
@@ -267,18 +295,32 @@ func (that *TestApp) PrintCoverage() CoverageReport {
|
||||
fmt.Println("总接口: 0")
|
||||
}
|
||||
|
||||
fmt.Println("\n已覆盖的接口:")
|
||||
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)
|
||||
} else if d.HasTest {
|
||||
fmt.Printf(" + %s\t(已定义, 未运行)\n", d.Path)
|
||||
if !isPartialRun {
|
||||
var ranDetails []MethodCoverage
|
||||
for _, d := range report.Details {
|
||||
if d.HasTest && d.CaseCount > 0 {
|
||||
ranDetails = append(ranDetails, d)
|
||||
}
|
||||
}
|
||||
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(report.Missing) > 0 {
|
||||
fmt.Println("\n未覆盖的接口:")
|
||||
fmt.Printf("\n未覆盖的接口: (%d 个)\n", len(report.Missing))
|
||||
for _, path := range report.Missing {
|
||||
fmt.Println(" -", path)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user