Golang测试触发panic:无法找到模板文件路径
Go测试触发Panic:找不到模板文件路径
报错信息
PS D:\projetos go\api-ranking-crypto> go test ./test/ panic: open template/layout-main-page.html: The system cannot find the path specified. goroutine 1 [running]: html/template.Must(...) D:/Go/src/html/template/template.go:374 github.com/maickmachado/upvote-api/controllers.init() D:/projetos go/api-ranking-crypto/controllers/controllers.go:15 +0x1d8 FAIL github.com/maickmachado/upvote-api/test 0.209s FAIL
问题原因
控制器包的全局变量在包初始化阶段就执行了template.ParseFiles,使用的是相对路径template/xxx.html。但运行测试时,工作目录是./test/,该目录下不存在template文件夹,导致文件查找失败触发panic。
即便测试的HealthCheck函数完全不依赖模板,包初始化代码也会优先执行,因此必然触发错误。
解决方案
方案1:使用绝对路径加载模板
通过Go的runtime和filepath包获取项目根目录,拼接模板的绝对路径,避免工作目录变化影响路径解析。修改控制器代码如下:
package controllers import ( "html/template" "io" "net/http" "path/filepath" "runtime" ) var ( _, currentFile, _, _ = runtime.Caller(0) // 根据目录结构向上回溯到项目根目录 projectRoot = filepath.Dir(filepath.Dir(currentFile)) TmplMainPage = template.Must(template.ParseFiles(filepath.Join(projectRoot, "template/layout-main-page.html"))) TmplDetailPage = template.Must(template.ParseFiles(filepath.Join(projectRoot, "template/layout-detail-page.html"))) TmplError = template.Must(template.ParseFiles(filepath.Join(projectRoot, "template/layout-erro.html"))) TmplRanking = template.Must(template.ParseFiles(filepath.Join(projectRoot, "template/layout-ranking.html"))) ) // 其他函数保持不变
方案2:指定测试的工作目录
运行测试时切换到项目根目录,而非test目录:
cd D:\projetos go\api-ranking-crypto go test ./test/
若使用IDE,可在测试配置中把工作目录设置为项目根目录。
方案3:延迟模板加载(更灵活)
将模板加载逻辑从全局变量初始化移到函数内部,或提供初始化函数,仅在需要使用模板时才执行加载:
package controllers import ( "html/template" "io" "net/http" "path/filepath" "runtime" ) var ( tmplMainPage *template.Template tmplDetailPage *template.Template tmplError *template.Template tmplRanking *template.Template projectRoot string ) func init() { _, currentFile, _, _ = runtime.Caller(0) projectRoot = filepath.Dir(filepath.Dir(currentFile)) } func initTemplates() error { var err error tmplMainPage, err = template.ParseFiles(filepath.Join(projectRoot, "template/layout-main-page.html")) if err != nil { return err } tmplDetailPage, err = template.ParseFiles(filepath.Join(projectRoot, "template/layout-detail-page.html")) if err != nil { return err } tmplError, err = template.ParseFiles(filepath.Join(projectRoot, "template/layout-erro.html")) if err != nil { return err } tmplRanking, err = template.ParseFiles(filepath.Join(projectRoot, "template/layout-ranking.html")) return err } // 在需要使用模板的函数中先检查初始化状态 func GetAllData(w http.ResponseWriter, r *http.Request) { if tmplMainPage == nil { if err := initTemplates(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } // 后续模板渲染逻辑 }
这种方式下,测试HealthCheck时不会触发模板加载,也就不会出现panic。
内容的提问来源于stack exchange,提问作者Maick Machado
相关产品推荐
相关产品推荐

