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:
(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.
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.
You could use ioutil.TempDir or TempFile from the same package.
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...}"))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With