初始化函数破坏单元测试

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

Init function breaking unit tests

问题

在我要测试的包中,我有一个初始化函数,它加载包含我想要用来运行应用程序的一些内容的配置文件。然而,在运行单元测试时,我不想触发这个初始化函数。

有没有办法在单元测试期间跳过或阻止调用这个初始化函数?

以下是一些代码片段来说明这个问题:

func init() {
    var err error // 防止 config 变量被遮蔽
    config, err = loadConfig("./client/config.yml")
    if err != nil {
        log.Fatal(err)
    }
}

func loadConfig(filepath string) (*Config, error) {
    viper.SetConfigFile(filepath)
    if err := viper.ReadInConfig(); err != nil {
        return nil, fmt.Errorf("加载配置文件时出错:%s", err)
    }
    (...)
}

// New 返回一个 Config 值
func New() Config {
    return *config
}

一个测试用例

func TestNew(t *testing.T) {
    expected := &Config{}
    observed := New()
    if !reflect.DeepEqual(observed, expected) {
        t.Errorf("观察到的值为 %+v,期望的值为 %+v\n", observed, expected)
    }
}
英文:

In the package I want to test, I have an init function that loads the configuration file containing some stuff I want to use to run my application. However, I don't want to trigger this init function while running my unit tests.

Is there any way for skipping or preventing this init function to be called during the unit tests?

Some snippets to illustrate the question:

func init() {
	var err error // Necessary to prevent config variable shadowing
	config, err = loadConfig("./client/config.yml")
	if err != nil {
		log.Fatal(err)
	}
}

func loadConfig(filepath string) (*Config, error) {
	viper.SetConfigFile(filepath)
	if err := viper.ReadInConfig(); err != nil {
		return nil, fmt.Errorf("Error loading config file: %s", err)
	}
  (...)
}

// New returns a Config value(!)
func New() Config {
	return *config
}

A test case:

func TestNew(t *testing.T) {
	expected := &Config{}
	observed := New()
	if !reflect.DeepEqual(observed, expected) {
		t.Errorf("observed %+v. expecting %+v\n", observed, expected)
	}
}

答案1

得分: 15

我不确定是否有更好的方法来做这个,但是如果你考虑到在运行init函数之前,包级别的变量会被初始化,你可以使用一个标志来判断你是否正在运行测试。

var _testing = false

func init() {
    if _testing {
        return
    }

    var err error // 防止变量config被遮蔽
    config, err = loadConfig("./client/config.yml")
    if err != nil {
        log.Fatal(err)
    }
}

// ...

在你的测试文件中你可以这样做

```go
// 不太好看,但是有效
var _ = (func() interface{} {
    _testing = true
    return nil
}())

func TestNew(t *testing.T) {
    expected := &Config{}
    observed := New()
    if !reflect.DeepEqual(observed, expected) {
        t.Errorf("observed %+v. expecting %+v\n", observed, expected)
    }
}

你可以在这里阅读更多关于初始化顺序的信息:https://golang.org/ref/spec#Program_initialization_and_execution

英文:

I'm not sure whether there's a nicer way of doing this, but if you consider the fact that package-level variables are initialized before the init func is run you can use a flag to tell you whether you're running tests or not.

var _testing = false

func init() {
    if _testing {
        return
    }

    var err error // Necessary to prevent config variable shadowing
    config, err = loadConfig("./client/config.yml")
    if err != nil {
        log.Fatal(err)
    }
}

// ...

And in your test file you could do something like this:

// not nice but works
var _ = (func() interface{} {
	_testing = true
	return nil
}())

func TestNew(t *testing.T) {
    expected := &Config{}
    observed := New()
    if !reflect.DeepEqual(observed, expected) {
        t.Errorf("observed %+v. expecting %+v\n", observed, expected)
    }
}

You can read more on the initialization order here: https://golang.org/ref/spec#Program_initialization_and_execution

huangapple
  • 本文由 发表于 2017年4月14日 18:41:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/43409919.html
匿名

发表评论

匿名网友

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

确定