Golang测试临时目录

huangapple go评论78阅读模式
英文:

golang test temp directory

问题

我有一个简单的函数,它将配置文件解析为JSON格式。我想编写一个测试,要么使用一些样本静态配置文件并解析它们,要么在测试期间创建样本并尝试解析它们。

虽然这不是问题的关键,但以下是基本代码:

// config.go

// ...(package,imports)...

// Overall settings - corresponds to main.conf
type MainSettings struct {
// stuff
}

// 从指定的文件路径加载 main.conf
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

}

以及测试代码:

// config_test.go

func TestLoadMainSettings(t *testing.T) {

// 可能生成一些示例配置文件,
// 或使用与源代码一起打包的静态样本

s, err := LoadMainSettings("conf/main.conf") // <-- 这个路径应该是什么??
if err != nil { panic(err) }

// 更多的合理性检查...

}

那么,我的具体问题是:

  • 是否有一个适合存放仅适用于测试的静态资源(如示例配置文件)的合适位置?
  • 在测试执行期间,是否有一个适当的(跨平台,与"go clean"一起清理)位置来写入临时文件?

(注意:我在Linux上进行大部分的暂存和生产环境运行,而在Mac上进行本地开发-因此在实践中,对于测试来说,在/tmp/作为临时目录是可行的。但是我想知道是否有更好的方法...)

编辑: 最终在测试中使用了以下方法:

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())

但是将 LoadMainSettings 接受 io.Reader 而不是 string 的建议也是一个好主意。

英文:

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 := &amp;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(&quot;conf/main.conf&quot;) // &lt;-- 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(&quot;&quot;, &quot;testmainconf&quot;)
if err != nil { panic(err) }
defer syscall.Unlink(f.Name())
ioutil.WriteFile(f.Name(), []byte(&quot;{...sample config data...}&quot;), 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.

答案1

得分: 30

自Go版本1.15起,标准的testing包中现在有T.TempDir()方法。文档对其进行了如下解释:

> TempDir返回一个供测试使用的临时目录。当测试及其所有子测试完成时,Cleanup会自动删除该目录。每次调用t.TempDir都会返回一个唯一的目录;如果目录创建失败,TempDir会通过调用Fatal终止测试。

英文:

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.

答案2

得分: 14

你可以使用ioutil.TempDir或者同一包中的TempFile。

英文:

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

答案3

得分: 10

只是为了与您使用ioutil.TempDir进行比较,这里展示了使用io.Reader的情况:

// 从指定的文件路径加载main.conf
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
}

具体来说,我们将参数从path字符串更改为srcio.Reader实例,并将ioutil.ReadFile替换为ioutil.ReadAll

您编写的测试用例变得更短,因为我们可以省去文件操作:

s, err := LoadMainSettings(strings.NewReader("{...示例配置数据...}"))
英文:

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 := &amp;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(&quot;{...sample config data...}&quot;))

答案4

得分: 0

你也可以这样做:

uniqueTempDir, err := os.MkdirTemp(os.TempDir(), "*-myOptionalSuffix")
if err != nil {
	return err
}
英文:

You can do this too:

uniqueTempDir, err := os.MkdirTemp(os.TempDir(), &quot;*-myOptionalSuffix&quot;)
if err != nil {
	return err
}

答案5

得分: 0

你可以这样做:

go env -w GOTMPDIR="C:\Users\<user>\go\tmp"
英文:

You can do this:

go env -w GOTMPDIR=&quot;C:\Users&lt;user&gt;\go\tmp&quot;

huangapple
  • 本文由 发表于 2013年9月30日 02:46:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/19081884.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定