【问题标题】:How do I know I'm running within "go test"我怎么知道我在“go test”中运行
【发布时间】:2012-12-24 07:50:15
【问题描述】:

当我运行“go test”时,我想使用不同的配置文件。我如何在我的代码中知道我是在测试上下文还是正常上下文中运行?是否需要检查某种环境变量?

【问题讨论】:

  • 你有没有找到一个好的解决方案?我正在处理与您几乎完全相同的配置设置的完全相同的问题。

标签: unit-testing go


【解决方案1】:

测试包在加载时会修改全局环境:它注册了很多命令行标志。因此,我们可以检查这些标志是否已注册:

func init() {
    if flag.Lookup("test.v") == nil {
        fmt.Println("normal run")
    } else {
        fmt.Println("run under go test")
    }
}

【讨论】:

  • 请务必注意,如果您在任何非 *_test.go 文件中导入测试,此方法将不起作用。它将始终假定测试运行。当我添加一些允许通过 testing.T 失败的实用程序函数时遇到了这个问题。
  • 实验上,这个答案似乎是正确的。重要的是要了解我们只想测试标志的存在/不存在(flag.Lookup("test.v") == nil),这表明测试框架已经注册了标志。此外,我们不关心标志的实际值是否存在(从 init() 中检查,很有可能它甚至还没有被解析)。
【解决方案2】:

由于flag.Lookup("test.v") 方法对我不起作用,我想分享我自己的解决方案:

strings.HasSuffix(os.Args[0], ".test")

或者

strings.Contains(os.Args[0], "/_test/")

两者似乎都有效。

【讨论】:

  • flag.Lookup("test.v") 方法过去可以工作,现在不行了(我使用的是 1.8.1)。
  • strings.HasSuffix(os.Args[0], ".test") 对我来说更可靠。有一台开发机器,strings.Contains(os.Args[0], "/_test/") 失败。
  • 这对我有用,而 flag.Lookup("test.v") 没有。事实上,当我查看flag.formal 地图(这是由flag.Lookup 索引的内容)时,根本没有任何标志。
【解决方案3】:

代码示例会有所帮助。但是从您的问题来看,您可能想在某个地方硬编码配置文件的路径,而您可能想将其传递进去。

更改您正在测试的函数以获取定义配置文件的参数,然后在您的测试代码中传递与您在非测试代码中使用的路径不同的路径。在测试与生产时,您的代码采用不同的路径是不好的做法。

【讨论】:

  • 我没有硬编码路径。我对每个环境(开发、测试版、产品等)都有不同的配置文件。我想要一个在运行“go test”时使用的“单元测试”环境。现在,我不得不做“ENV=test go test ./...”,这很麻烦。我希望有一些东西我可以测试“去测试”设置自己。
  • 然后让您的测试函数使用 dev 配置文件作为其设置的一部分。这不应该根据将在生产中运行的代码来确定。这是在自找麻烦。
  • 我同意杰里米的观点。无论是否运行测试,都不应检测到配置路径。那个代码有味道。你应该明确地写一个路径——一个在 main 函数中,第二个在你的 test 函数中。不要隐藏你的依赖。
【解决方案4】:

一种可能性是使用build constraints。如果您将go test 运行为:

go test -tags testing pkgname

然后您可以使用该标签来选择哪些文件将包含在您的包的标准构建中,哪些文件将用于测试。

如果您将标准配置放在自己的文件中,则在顶部添加一行如下所示将确保它不用于测试:

// +build !testing

然后您可以将测试配置包含在*_test.go 文件之一中,或包含在需要设置testing 标记的其他文件中。

【讨论】:

  • 理想情况下,不应该有任何必要的魔法词来指示代码在单元测试上下文中运行。 "go test" 应该设置 something 表明这是单元测试。
  • 不,不应该。你是对的,不应该有一个神奇的词来指示在单元测试上下文中运行。不是来自 go test 也不是来自你。你的测试应该有一个不同的函数来设置你的测试文件然后显式调用的测试环境
  • “不同的功能设置”的问题在于它依赖于工程师的努力。如果我的框架需要在我的框架用户测试期间更换模拟测试位,我希望在我作为框架设计者的控制下自动完成。请注意,这并不排除测试在测试期间对我的框架行为进行改进的能力。但它确实依赖于我知道我何时在测试环境中运行的能力。
【解决方案5】:

flag.Lookup("test.v") == nil 方法似乎有效,但我建议使用TestMain,它专门设计用于允许特定设置和拆卸测试。如果您在要测试的包中包含此方法,它将在您的单独测试之前调用,因此您可以在调用 m.Run() 之前设置全局标志或执行您想要执行的任何测试特定配置,如下所示

func TestMain(m *testing.M) {
    // test context initialization here
    os.Exit(m.Run())
}

PS:这实际上是@calvin-sugianto 建议的,只是与 Gin 无关

【讨论】:

  • 这似乎是最好的答案,因为它记录在 golang.org 上并将继续得到支持。 imo 应避免基于未记录标志的答案。
  • 这点很好,但是有在init()之前没有被调用的问题,所以不能用来控制init()的动作
【解决方案6】:

flag.Lookup("test.v") 解决方案对我也不起作用(转到 1.13),而且我有很多服务要维护,在每个服务中都使用func TestMain(m *testing.M) 解决方案是不可行的。由于所有服务共享一个公共库,因此我提出了以下解决方案:

func isInTests() bool {
    for _, arg := range os.Args {
        if strings.HasPrefix(arg, "-test.v=") {
            return true
        }
    }
    return false
}

这类似于flag.Lookup("test.v") 解决方案,因为我们检查-test.v 是否存在。

EDIT:根据@mh-cbon 注释更新代码

【讨论】:

  • 我会做if strings.HasPrefix(arg, "-test.") {。如果 -v 标志设置为 false,您的代码将无法捕获正在运行的测试。
【解决方案7】:

我是 golang 新手,flag.Lookup("test.v") 对我不起作用,所以我找到了通过在 init() 中设置 ENV 变量来识别上下文是测试还是正常的方法。

如果您有测试文件,例如 abc.text.go,请将环境变量“GO_ENV”设置为 init() 中的测试。

func init() {
    os.Setenv("GO_ENV", "testing")
}

你想知道上下文的任何地方都可以使用 os.Getenv("GO_ENV")
abc.go

if os.Getenv("GO_ENV") == "testing" {

} else {

}

【讨论】:

    【解决方案8】:

    与 Pram 的回答类似,我可能会在您运行测试时设置一个环境变量。

    生成文件

    test:
     ENV=testing go test ./...
    

    main.go

      env := os.Getenv("ENV")
    

    【讨论】:

      【解决方案9】:

      Garrett 的解决方案更强大:

       func init() {
          if v := flag.Lookup("test.v"); v == nil || v.Value.String() != "true" {
              fmt.Println("normal run")
          } else {
              fmt.Println("run under go test")
          }
       }
      

      【讨论】:

      • 这不是加勒特的,这是我的答案。而且我们不需要知道这个标志的值,我们只需要知道包“test”被加载并注册了这个标志。
      • 我在野外看到了这种用法,并想重申@Powerman 的评论,即它不正确。测试真/假值实际上是测试是否给出了详细测试标志,这是无关紧要的。此外,如果在 init() 中使用,很可能 flag.Parse() 尚未被调用,因此无法使用该值。检查 flag.Lookup("test.v") != nil 就足以检测测试框架。
      【解决方案10】:

      如果您尝试检测文件是通过“go run”还是可执行文件运行,此函数会检查目录是否包含“/Temp/go-build”(还检查 \ 是否支持 Windows)

      if strings.Index(os.Args[0], "/Temp/go-build") != -1 || strings.Index(os.Args[0], "\\Temp\\go-build") != -1 {
          // ran with go run
      } else {
          // ran as executable file
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-23
        相关资源
        最近更新 更多