英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论