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

1 回复

更多关于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(嵌入文件系统)可以确保静态文件始终可用,无论测试在哪里运行。

回到顶部