在我的程序和单元测试中无法使用相同的相对路径。

huangapple go评论82阅读模式
英文:

Unable to use the same relative path in my program AND my unit tests

问题

在我的Go项目中,我使用一个函数来打开一个特定的文件并返回其内容。该文件存储在另一个目录中,但仍然在我的项目目录内。

package infrastructure

func openKey() ([]byte, error) {
    if path, err := filepath.Abs("../security/key.rsa"); err != nil {
        return nil, err
    } 

    return ioutil.ReadFile(path)
}

如果我从单元测试中调用这个函数,它是可以工作的。但是如果我在我的程序中调用相同的函数,我会遇到以下错误:

2015/08/13 15:47:54 open
/me/go/src/github.com/myaccount/security/key.rsa: 没有这个文件或目录

文件的正确绝对路径是:

/me/go/src/github.com/myaccount/myrepo/security/key.rsa

使用openKey函数的两个代码(来自我的程序和单元测试)都在同一个包infrastructure中。

这是我执行程序的方式:

go install && ../../../../bin/myproject

这是我执行单元测试的方式:

go test ./...

最后,这是我的项目的目录结构:

go/src/github.com/myaccount/myrepo/:
- main.go
- security:
    - key.rsa // 我想要打开的文件
    - ...
- infrastructure
    - openFile.go // 包含`openKey`函数的文件
    - server.go // 调用`openKey`函数的文件
    - openFile_test.go // 调用`openKey`函数的单元测试

编辑:

这是我的程序二进制文件所在的绝对路径:

/Users/me/Documents/Développement/Jean/go/bin

这是我的单元测试所在的路径:

/var/folders/tj/8ywtc7pj3rs_j0y6zzldwh5h0000gn/T/go-build221890578/github.com/myaccount/myrepo/infrastructure/_test

有什么建议吗?谢谢!

英文:

In my Go Project I use a function that opens a specific file and returns its content. The file is stored in another directory but still inside my project directory.

package infrastructure

func openKey() ([]byte, error) {
	if path, err := filepath.Abs("../security/key.rsa"); err != nil {
		return nil, err
	} 

    return ioutil.ReadFile(path)
}

This function works if I call it from a unit test. But if I call the same function in my program, I've this error:

> 2015/08/13 15:47:54 open
> /me/go/src/github.com/myaccount/security/key.rsa: no such file
> or directory

The correct absolute path of the file is:

> /me/go/src/github.com/myaccount/myrepo/security/key.rsa

Both code that use the openKey function (from my program and unit test) are in the same package: infrastructure

Here is how I execute my program:

> go install && ../../../../bin/myproject

And how I execute my unit tests:

> go test ./...

And finally the directory structure of my project:

go/src/github.com/myaccount/myrepo/: 
- main.go
- security:
    - key.rsa // The file that I want to open
    - ...
- infrastructure
    - openFile.go // The file with the func `openKey``
    - server.go // The file with the func that call the func `openKey`
    - openFile_test.go // The unit test that calls the func `openKey`

Edit:

Here are the absolute paths of where the binary of my program is located:

> /Users/me/Documents/Développement/Jean/go/bin

And where my unit tests are located:

> /var/folders/tj/8ywtc7pj3rs_j0y6zzldwh5h0000gn/T/go-build221890578/github.com/myaccount/myrepo/infrastructure/_test

Any suggestion?
Thanks!

答案1

得分: 3

首先,当你运行测试时,不应该使用与生产应用程序运行时相同的文件。因为测试文件对于所有具有存取库权限的人都是可访问的,这是一个安全问题。

正如评论中所说,问题在于当运行测试时,工作目录是源代码的目录(实际上,在运行测试之前,会将整个代码复制到临时目录中),而当你真正运行程序时,工作目录是你从中运行命令的目录,因此相对路径是错误的。

我建议的做法是使用配置选项来获取要加载文件的路径(或用于路径的基本目录)。可以使用环境变量(我强烈建议这样做,详见12因素宣言),配置文件,命令行标志等方式来实现。

英文:

First, you shouldn't use the same files when running your tests than when running your application in production. Because the test files are accessible to everyone that has access to the repository, which is a security fail.

As said in the comments, the problem is that when running your tests, the working directory is these of the source code (in fact, go copy the whole bunch into a temp directory prior to running the tests), while when you run the program for real, the working directory is the one you are running the command from, hence the wrong relative path.

What I would advise is to use a configuration option to get a the file from which load your file (or a base directory to use with your paths). Either using an environment variable (I strongly encourage you to do that, see the 12factors manofesto for details), a configuration file, a command-line flag, etc.

答案2

得分: 0

go test ./... 命令在运行该目录下的测试之前,会将当前目录更改为 go/src/github.com/myaccount/myrepo/infrastructure。因此,测试中的所有相对路径都是相对于 infrastructure 目录的。

一个简单而健壮的允许测试的方法是改变函数的签名。

func openKey(relPath string) ([]byte, error) {
    if path, err := filepath.Abs(relPath); err != nil {
        return nil, err
    } 

    return ioutil.ReadFile(path)
}

这样你就可以在测试期间自由地将 key.rsa 放置在任何位置,例如可以将其复制并存储在 infrastructure 目录中。

更加优雅和健壮的方法是使用 io.Reader

func openKey(keyFile io.Reader) ([]byte, error) {
    return ioutil.ReadAll(keyFile)
}

这样你就可以在测试中传递一个 strings.Reader,这意味着你可以在不依赖文件系统的情况下测试代码。但在这种情况下可能有点过度设计。

英文:

The go test ./... command changes the current directory to go/src/github.com/myaccount/myrepo/infrastructure before running the tests in that directory. So all relative paths in the tests are relative to the infrastructure directory.

A simple, robust way to allow testing would be to change the signature of your function.

func openKey(relPath string) ([]byte, error) {
    if path, err := filepath.Abs(relPath); err != nil {
        return nil, err
    } 

    return ioutil.ReadFile(path)
}

This gives you freedom to place key.rsa anywhere during testing, you can for example make a copy of it and store it in infrastructure

An even more elegant and robust way would be to use io.Reader

func openKey(keyFile io.Reader) ([]byte, error) {
    return ioutil.ReadAll(keyFile)
}

since you can pass it a strings.Reader for testing. This means that you can test your code without having to rely on the filesystem at all. But that's probably overkill in this case.

huangapple
  • 本文由 发表于 2015年8月13日 21:59:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/31990342.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定