You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 15:20:32