[英]Golang: tests and working directory
我正在为 Go 中的应用程序编写一些单元测试。但是测试失败了,因为它找不到配置文件。 通常,二进制文件在路径conf/*.conf
下的工作目录中查找配置文件。
我认为浏览到具有conf/
的目录并在其中运行go test
可以解决它,但它仍然报告文件系统找不到指定的路径。
我如何告诉go test
使用某个目录作为工作目录,以便实际执行测试?
您可以使用 Caller 获取当前测试源文件的路径,如下所示:
package sample
import (
"testing"
"runtime"
"fmt"
)
func TestGetFilename(t *testing.T) {
_, filename, _, _ := runtime.Caller(0)
t.Logf("Current test filename: %s", filename)
}
我不相信这是可能的。 我无法找到明确说明这一点的文档,但我相信go test
总是使用包目录(包含 go 源文件)作为工作目录。
作为一种解决方法,我编译了测试并从当前目录执行测试。
go test -c && ./<mypackage>.test
或者,如果您想要一个可以使用的通用命令,您可以使用-o
选项重命名测试文件。
go test -c -o xyz.test && ./xyz.test
虽然不是很方便,但您始终可以将其作为命令行变量传递,例如:
package blah_test
import (
"flag"
"fmt"
"os"
"testing"
)
var (
cwd_arg = flag.String("cwd", "", "set cwd")
)
func init() {
flag.Parse()
if *cwd_arg != "" {
if err := os.Chdir(*cwd_arg); err != nil {
fmt.Println("Chdir error:", err)
}
}
}
func TestBlah(t *testing.T) {
t.Errorf("cwd: %+q", *cwd_arg)
}
然后像这样运行它:
┌─ oneofone@Oa [/tmp]
└──➜ go test . -cwd="$PWD"
--- FAIL: TestBlah (0.00 seconds)
blah_test.go:16: cwd: "/tmp"
无论工作目录在哪里。 它必须在您的项目目录下。 所以我的解决方案是
wd, _ := os.Getwd()
for !strings.HasSuffix(wd, "<yourProjectDirName>") {
wd = filepath.Dir(wd)
}
raw, err := ioutil.ReadFile(fmt.Sprintf("%s/src/conf/conf.dev.json", wd))
您的路径应始终从您的项目目录开始。 每次您读取包中的文件并通过 main.go 或您的另一个包单元测试访问时。 它会一直工作。
将 init 函数添加到测试包下的 *_test.go 中。 测试包将在测试功能启动之前运行此功能。
func init() {
_, filename, _, _ := runtime.Caller(0)
// The ".." may change depending on you folder structure
dir := path.Join(path.Dir(filename), "..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}
}
您可以使用os 包。
你会想做这样的事情
func TestMyFunction(t *testing.T) {
os.Chdir("./path")
//TEST FUNCTION
os.Chdir("..")
}
os 包中有几种可能性。
我遇到了类似的问题,并在此博客上找到了解决方案
基本上,您可以使用类似的功能更改测试正在运行的文件夹:
package main
import (
"os"
"path"
"runtime"
)
func MakeFunctionRunOnRootFolder() {
_, filename, _, _ := runtime.Caller(0)
// The ".." may change depending on you folder structure
dir := path.Join(path.Dir(filename), "..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}
}
我知道这是一个老问题,但我在尝试在测试中使用数据库迁移时遇到了同样的问题,也许这个解决方案可以帮助某人。
由于没有获取项目目录的本机方式,您可以识别一些您知道它仅位于项目根目录中的文件或目录(在我的情况下,它是相对目录database/migrations )。 一旦你有了这个唯一的相对目录,你就可以有一个像下面这样的函数来获取项目根目录。 它只是获取当前的工作目录(假设它在项目目录中)并开始一直向上导航,直到找到一个具有相对目录的目录,您知道它位于项目的根目录:
func FindMyRootDir() string {
workingDirectory, err := os.Getwd()
if err != nil {
panic(err)
}
lastDir := workingDirectory
myUniqueRelativePath := "database/migrations"
for {
currentPath := fmt.Sprintf("%s/%s", lastDir, myUniqueRelativePath)
fi, err := os.Stat(currentPath)
if err == nil {
switch mode := fi.Mode(); {
case mode.IsDir():
return currentPath
}
}
newDir := filepath.Dir(lastDir)
// Ooops, we couldn't find the root dir. Check that your "myUniqueRelativePath" really exists
if newDir == "/" || newDir == lastDir {
return ""
}
lastDir = newDir
}
}
当然,这不是最漂亮的解决方案,但它确实有效。
我会使用环境变量作为您应用程序的位置。 这似乎是运行 go 工具的最佳方式,因为测试程序可以从临时位置运行。
// get home dir of app, use MYAPPHOME env var if present, else executable dir.
func exeDir() string {
dir, exists := os.LookupEnv("MYAPPHOME")
if exists {
return dir
} else {
ex, err := os.Executable()
if err != nil {
panic(err)
}
exPath := path.Dir(ex)
return exPath
}
}
我目前使用一个简洁的解决方案来解决这个问题,而不是通过调用os.Open()
直接打开文件,我以一种聪明的方式使用嵌入 package:
首先,我在根目录 package 中创建了一个全局变量,名为:
//go:embed config/* otherdirectories/*
var RootFS embed.FS
然后我使用这个全局变量打开测试中的文件,例如:
func TestOpenConfig(t *testing.T) {
configFile, err := rootpkg.RootFS.ReadFile("config/env")
if err != nil {
t.Fatalf("unable to open config/env file: %s", err)
}
if string(configFile) != "FOO=bar\n" {
t.Fatalf("config file contents differ from expected: %s", string(configFile))
}
}
这是一个巧妙的技巧,因为现在您始终可以使用根目录 package 的相对路径,这是我以前在其他编程语言中所做的。
当然,这有一个限制,你需要导入你的根 package,这取决于你的 package 布局,因为循环导入可能并不理想。 如果是这种情况,您可能只需在配置目录本身内创建一个embed.go
文件,然后按名称调用您的配置。
另一个缺点是你在二进制文件中嵌入了测试文件,如果你的测试文件不是很大,比如几兆字节,这可能没问题,所以我不太介意这个问题。
我还创建了一个存储库来说明这个解决方案:
https://github.com/VinGarcia/golang-reading-files-from-tests
Go 1.20 正在为“go 子命令”获取新的-C
arguments,因此这应该有所帮助:
go test -C directory/ ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.