Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

golang test temp directory

Tags:

file

testing

go

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 a string is also a good idea.

like image 656
Brad Peabody Avatar asked Sep 29 '13 18:09

Brad Peabody


3 Answers

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.

like image 74
jochen Avatar answered Nov 18 '22 15:11

jochen


You could use ioutil.TempDir or TempFile from the same package.

like image 26
Ask Bjørn Hansen Avatar answered Nov 18 '22 15:11

Ask Bjørn Hansen


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...}"))
like image 10
dyoo Avatar answered Nov 18 '22 15:11

dyoo