dongli8722
dongli8722
2015-08-13 13:59

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

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!

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

2条回答

  • douchang8758 douchang8758 6年前

    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.

    点赞 评论 复制链接分享
  • doukeyong3746487 doukeyong3746487 6年前

    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.

    点赞 评论 复制链接分享

为你推荐