golang test temp directory
Solution 1
Just to compare vs. what you have with ioutil.TempDir
, here's what things look like with io.Reader
:
// Load main.conf from the specified file path
func LoadMainSettings(src io.Reader) (*MainSettings, error) {
b, err := ioutil.ReadAll(src)
if err != nil { return nil, err }
r := &MainSettings{}
err = json.Unmarshal(b, r)
if err != nil { return nil, err }
return r, nil
}
Specifically, we change the argument from a path
string to a src
io.Reader
instance, and we replace the ioutil.ReadFile
with an ioutil.ReadAll
.
The test case that you've written then ends up being a bit shorter precisely because we can dispense with file operations:
s, err := LoadMainSettings(strings.NewReader("{...sample config data...}"))
Solution 2
Since Go version 1.15 there is now T.TempDir()
in the standard testing
package. The docs explain it as follows:
TempDir returns a temporary directory for the test to use. The directory is automatically removed by Cleanup when the test and all its subtests complete. Each subsequent call to t.TempDir returns a unique directory; if the directory creation fails, TempDir terminates the test by calling Fatal.
Solution 3
You could use ioutil.TempDir or TempFile from the same package.
Related videos on Youtube
Comments
-
Brad Peabody over 1 year
I have a simple function which parses a config file as JSON. I want to write a test which either uses some sample static config files and parses them, or creates the samples during the test and tries to parse them.
It's not entirely necessary to the question, but here is the basic code:
// config.go // ...(package,imports)... // Overall settings - corresponds to main.conf type MainSettings struct { // stuff } // Load main.conf from the specified file path func LoadMainSettings(path string) (*MainSettings, error) { b, err := ioutil.ReadFile(path) if err != nil { return nil, err } r := &MainSettings{} err = json.Unmarshal(b, r) if err != nil { return nil, err } return r, nil }
and the test:
// config_test.go func TestLoadMainSettings(t *testing.T) { // possibly generate some example config files, // or use static samples packaged with the source s, err := LoadMainSettings("conf/main.conf") // <-- what should this path be?? if err != nil { panic(err) } // more sanity checking... }
That said, my specific questions are:
- Is there a proper place for static assets (like sample config files) that are only applicable to tests?
- During test execution is there a proper (cross platform, gets cleaned up with 'go clean') location to write out temporary files?
(Note: I run most of my stuff on Linux for staging and production and Mac for local dev - so using /tmp/ as a temp dir for tests works for me in practice. But was wondering if there's a better way...)
EDIT: Ended up using this approach for the test:
f, err := ioutil.TempFile("", "testmainconf") if err != nil { panic(err) } defer syscall.Unlink(f.Name()) ioutil.WriteFile(f.Name(), []byte("{...sample config data...}"), 0644) s, err := LoadMainSettings(f.Name())
But the other suggestion of making LoadMainSettings accept an
io.Reader
instead of astring
is also a good idea.-
dyoo over 10 yearsCan you write your test so it uses an
io.Reader
directly? If so, then your test case won't need to depend on the file system, as your tests can usestrings.NewReader
to provide the appropriate test content in the test itself. -
Tyler over 10 yearsIt shouldn't be more cumbersome for the caller. A file is an
io.Reader
already.