Golang测试静态文件及正确路径获取方法
Golang测试静态文件及正确路径获取方法 我是Go语言的新手,正在尝试通过这个教程(https://www.sohamkamani.com/golang/how-to-build-a-web-application/#testing-the-static-file-server)来理解如何为静态文件编写测试。我对项目做了一些修改,这些都能正常工作,但如果我把测试移到tests文件夹中,就会收到404未找到错误,因为找不到assets目录下的index.html文件。
fmt.Println(resp);
&{404 Not Found 404 HTTP/1.1 1 1 map[Content-Length:[19] Content-Type:[text/plain; charset=utf-8] Date:[Fri, 22 Apr 2022 12:40:07 GMT] X-Content-Type-Options:[nosniff]] 0xc0001a0080 19 [] false false map[] 0xc00012c100 <nil>}
但是,如果我将assets文件夹复制到tests文件夹中,就不会出现错误。我的项目结构如下:
MyProject
tests
---main_test.go
assets
---index.html
handler
---handlers.go
mainfunc
---funcs.go (newRouter()-function goes hier)
main.go
go.mod
我认为问题出在这里:
resp, err := http.Get(mockServer.URL + "/assets/")
我该如何在这里设置正确的路径?
更新
tests/main_test.go
import (
m "myproject/mainfunc"
"net/http"
"net/http/httptest"
"testing"
)
func TestStaticFileServer(t *testing.T) {
r := m.NewRouter()
mockServer := httptest.NewServer(r)
defer mockServer.Close()
resp, err := http.Get(mockServer.URL + "/assets/")
if err != nil {
t.Fatal(err)
}
// 此处出错
if resp.StatusCode != http.StatusOK {
t.Errorf("Status should be 200, got %d", resp.StatusCode)
}
contentType := resp.Header.Get("Content-Type")
expectedContentType := "text/html; charset=utf-8"
// 此处出错
if expectedContentType != contentType {
t.Errorf("Wrong content type, expected %s, got %s", expectedContentType, contentType)
}
}
mainfunc/funcs.go
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
h "myproject/handler"
)
func NewRouter() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/hello", Handler).Methods("GET")
staticFileDirectory := http.Dir("./assets/")
staticFileHandler := http.StripPrefix("/assets/", http.FileServer(staticFileDirectory))
r.PathPrefix("/assets/").Handler(staticFileHandler).Methods("GET")
r.HandleFunc("/bird", h.GetBirdHandler).Methods("GET")
r.HandleFunc("/bird", h.CreateBirdHandler).Methods("POST")
return r
}
谢谢
更多关于Golang测试静态文件及正确路径获取方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang测试静态文件及正确路径获取方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题在于测试运行时的工作目录与项目根目录不同。当测试在 tests 目录中执行时,相对路径 ./assets/ 指向的是 tests/assets/ 而不是项目根目录下的 assets/。
以下是解决方案:
方案1:使用绝对路径(推荐)
通过 os.Getwd() 获取项目根目录,然后构建绝对路径:
import (
"os"
"path/filepath"
"runtime"
)
func NewRouter() *mux.Router {
r := mux.NewRouter()
// 获取项目根目录
_, b, _, _ := runtime.Caller(0)
basePath := filepath.Dir(b)
// 向上回溯到项目根目录(根据实际结构调整)
projectRoot := filepath.Dir(filepath.Dir(basePath))
// 构建assets的绝对路径
assetsPath := filepath.Join(projectRoot, "assets")
staticFileDirectory := http.Dir(assetsPath)
staticFileHandler := http.StripPrefix("/assets/", http.FileServer(staticFileDirectory))
r.PathPrefix("/assets/").Handler(staticFileHandler).Methods("GET")
// 其他路由...
return r
}
方案2:使用环境变量或配置 通过配置指定静态文件目录:
func NewRouter(staticDir string) *mux.Router {
r := mux.NewRouter()
staticFileDirectory := http.Dir(staticDir)
staticFileHandler := http.StripPrefix("/assets/", http.FileServer(staticFileDirectory))
r.PathPrefix("/assets/").Handler(staticFileHandler).Methods("GET")
return r
}
在测试中:
func TestStaticFileServer(t *testing.T) {
// 获取项目根目录
_, b, _, _ := runtime.Caller(0)
basePath := filepath.Dir(b)
projectRoot := filepath.Dir(filepath.Dir(basePath))
assetsPath := filepath.Join(projectRoot, "assets")
r := m.NewRouter(assetsPath)
mockServer := httptest.NewServer(r)
defer mockServer.Close()
resp, err := http.Get(mockServer.URL + "/assets/")
// ... 测试代码
}
方案3:使用嵌入文件系统(Go 1.16+)
使用 embed 包将静态文件嵌入到二进制中:
import "embed"
//go:embed assets/*
var staticFiles embed.FS
func NewRouter() *mux.Router {
r := mux.NewRouter()
// 使用嵌入的文件系统
staticFileHandler := http.StripPrefix("/assets/",
http.FileServer(http.FS(staticFiles)))
r.PathPrefix("/assets/").Handler(staticFileHandler).Methods("GET")
return r
}
方案4:修改测试工作目录 在测试开始时切换到项目根目录:
func TestStaticFileServer(t *testing.T) {
// 保存当前工作目录
originalWD, _ := os.Getwd()
defer os.Chdir(originalWD)
// 切换到项目根目录
_, b, _, _ := runtime.Caller(0)
basePath := filepath.Dir(b)
projectRoot := filepath.Dir(filepath.Dir(basePath))
os.Chdir(projectRoot)
r := m.NewRouter()
mockServer := httptest.NewServer(r)
defer mockServer.Close()
resp, err := http.Get(mockServer.URL + "/assets/")
// ... 测试代码
}
推荐使用方案1或方案3,特别是方案3(嵌入文件系统)可以确保静态文件始终可用,无论测试在哪里运行。

