0

我正在做一个 go 项目,我的任务是为一个包编写一些测试。测试需要访问不同包中的全局变量。这个全局变量可能在不同包的测试中设置/访问。因为默认情况下,go testing 会针对不同的包并行运行。因此,设置/访问此变量可能会产生竞争条件。

最简单的同步方法是创建一个共享的sync.Mutex,它跨越不同的包。话虽如此,我尝试将这个sync.Mutex放在声明全局变量的xxx.go的xxx_test.go中,不幸的是,由于范围限制,另一个包无法访问这个Mutex。最终,我发现我必须把这个sync.Mutex放到一个专门用于测试的实用程序包中,然后不同的包可以访问这个 Mutex 以实现该全局变量的同步目的。

我是新来的。我只是觉得我需要创建一个实用程序包来实现测试中的同步目的很尴尬,另一方面,如果另一个开发人员在另一个包中进行一些测试,他/她可能不知道在哪里可以找到这个同步.互斥量。有没有更好的方法可以通过优雅的解决方案来实现此同步目的。

非常感谢!

4

1 回答 1

2

这个问题不可能广泛。整本书都是关于这个主题的。

但是由于您专门询问了全局变量,因此最简单的答案是:不要使用全局变量。

我们总是被教导全局变量是一种反模式。测试是全局变量和单例是反模式的主要原因之一。

如果可能,重构您的全局状态以至少允许实例变量,而不是全局变量。然后您可以将该实例传递给您的函数进行测试。

作为一个简化的示例,假设您有以下全局变量和一个使用它的函数:

var globalFoo = 123

func doFoo() string {
    return fmt.Sprintf("foo = %d", globalFoo)
}

修改您的函数以将您的变量作为参数:

func doFoo(foo int) string {
    return fmt.Sprintf("foo = %d", foo)
}

如果你的全局状态是数据库连接,或者大量变量,这可能会更复杂,但原理是一样的:不要使用全局变量;而是传递变量。

在遗留代码库中,允许测试而不更改函数签名的一种方法是创建简单的包装函数:

func doFoo() string {
    return realDoFoo(globalFoo)
}

func realDoFoo(foo int) string {
    fmt.Sprintf("foo = %s", foo)
}
于 2017-08-16T12:09:35.150 回答