Go test - working directory keeps changing to dir of the test file, instead of value in template

Answered

Hi,

I have a Go project structure like this:

coolproject/
coolproject/testdata/inputs.txt
coolproject/pkg/processor/proc.go
coolproject/pkg/processor/proc_test.go

When I have proc_test.go open in GoLand, I can right-click a test case and select "Run 'TestProc_MyTest'" in the context menu.  This creates a Run Configuration of the Go Test type and executes it.  The problem is that the working directory is always set to coolproject/pkg/processor instead of coolproject/. It's an issue because my test case assumes working directory is coolproject and wants to load testdata/inputs.txt relative to it.

If I go to Run -> Edit Configurations -> expand 'Templates' on the left hand side, then click 'Go Test,' it tells me, "Template.  The values saved here will be used for new configurations of the same type."  However, even if I modify that field to /Users/coolguy/coolproject and then delete all existing Run Configurations, if I try to run a test by right clicking the test case (as mentioned above), the configuration it creates is still /Users/coolguy/coolproject/pkg/processor.

Is that a bug or is there some other way to configure this?

 

2
3 comments

I just realized that Go itself seems to have the convention of using the dir of the test file as the pwd when executing tests; i.e, `go test` will use the coolproject/pkg/processor as pwd.  So perhaps my project should be structured that way instead, making this issue less pressing for me.

0

Hello,

By default, running go test executes a package’s tests with the current working directory set to that package’s path. If you execute an `os.Getwd()` from within a test function, you'll see that your working directory is the package directory. The same directory is set when starting the configuration (regardless of the template).

There are two ways here:

1. Use relative paths to testdata in tests (not quite the correct and convenient way, but it works).
2. Use a special trick with Go's runtime package.

The trick is actually very simple and is to get the current executing and add `..` to the project root.

Create a new directory and file like `testing_init.go` with the following content:

```

package testing_init

import (
  "os"
  "path"
  "runtime"
)

func init() {
  _, filename, _, _ := runtime.Caller(0)
  dir := path.Join(path.Dir(filename), "..")
  err := os.Chdir(dir)
  if err != nil {
    panic(err)
  }
}

```

After that, just import the package into any of the test files:

```

package main_test

import (
  _ "project/testing_init"
)

```

Now you can specify paths from the project root (`testdata/inputs.txt` in your case).

Does it help?

4

@Daniil Maslov you're a legend. I can't believe another common functionality in all the other languages is once again missing in Go without weird ass workarounds 

1

Please sign in to leave a comment.