【问题标题】:Process command line arguments in go test在 go test 中处理命令行参数
【发布时间】:2014-02-16 12:38:34
【问题描述】:

有没有办法在 go "tests" 中获取命令行参数,
当您调用go test 时,显然您的main 没有运行,所以有没有办法处理命令行参数,

一种方法是使用 flags 包并检查每个测试或正在测试的函数中的命令行参数,但这并不理想,因为您需要在很多地方执行此操作,不像当您运行应用程序时,您只需在main 中即可。

有人可能会认为这样做是错误的,并且违反了单元测试的纯度:

  1. 并非所有测试都是单元测试
  2. 不依赖“ENV”变量并在命令行中实际将这些东西作为参数传递是非常实用的,

为了记录,我最终将init() 函数放在我的一个_test 文件中,并设置在以这种方式调用main 时通过标志设置的变量。

【问题讨论】:

  • 我不确定你在问什么。测试不应依赖于命令行参数。
  • 行为测试可以,单元测试不应该,比如是否需要知道它是在开发环境还是生产环境中?
  • 如果你绝对需要你可以使用-args 标志go testgo test -v -args --test-args foo
  • @Cubic 除非您想测试是否正确处理了命令行参数...

标签: testing go command-line-arguments go-flag


【解决方案1】:

根据我的经验,环境配置最好保存在环境变量中。您可以像这样依赖全局变量:

var envSetting = os.Getenv("TEST_ENV")

或者,如果需要使用标志,您可以将初始化代码放在名为 init() 的函数中。

func init() {
    flags.Parse()
    myEnv = *envFlag
    // ...
}

【讨论】:

  • 谢谢,你的意思是在依赖它的每个测试中调用 init,对,这个 init 不是一个神奇的测试设置,对吗?
  • 我建议在测试中仅使用环境变量以避免与测试运行程序的命令行参数发生冲突。
  • 我不确定 init() 技巧是否有效。任何名为 'init' 的函数在 main() 之前自动运行,但在调用 'go test' 时根本不运行 golang.org/ref/spec#Program_execution "无法从程序中的任何位置引用 init 函数。特别是不能调用 init显式地,也不能将指向 init 的指针分配给函数变量。”
  • @MatrixFrog - 你只是猜测还是发表声明?那个信息是假的。我在自己的测试中使用init就好了,为整个过程设置一些全局测试资源。
  • 我写了一个测试来验证在测试时没有调用init()。但我做错了——你是对的,仍然调用了 init()。对不起,没关系!
【解决方案2】:
os.Args[1] = "-conf=my.conf"
flag.Parse()

请注意,配置文件名是硬编码的。

【讨论】:

  • 如果 cli 没有传递任何参数,这将引发索引超出范围错误。显式覆盖 os.Args []string 可能是更好的选择。 os.Args = []string{"noop", "-flag1=val1", "arg1", "arg2"}
【解决方案3】:

另一种方法是让main() 成为一个存根,仅在flag.Parse() 处理参数后调用另一个函数,例如:

var flagvar int
func init() {
    flag.IntVar(&flagvar, "flagname", 1234, "help for flagname")
}

func main() {
    flag.Parse()
    submain(flag.Args)
}

func submain(args []string) {
   ...
}

然后在您的测试中,可以在调用submain(...) 模拟命令行建立标志和参数之前设置标志变量并建立参数。这种方法可用于最大化测试覆盖率,而无需实际使用命令行。例如,在 main_test.go 中,你可能会这样写:

func TestSomething(t *testing.T) {
    flagvar = 23
    args := []string{"a", "b", "c"}
    submain(args)
    ...
}

【讨论】:

  • 如果submain() 验证args(例如,--port 必须在 1025 和 65535 之间),你将如何构建一个测试,submain() 在不正确的情况下执行 os.Exit(1) --port 标志?
  • @nate 如果验证失败,解决方案可能是从 submain 返回错误并在您的测试中检查
【解决方案4】:

您可以直接测试主函数并传递参数。

显示一个标志和一对位置参数的简单示例

注意:不要将其称为对 Go 1.8 的测试框架具有特殊含义的“TestMain”。

package main

import (
    "os"
    "testing"
)

func TestMainFunc(t *testing.T) {

    os.Args = append(os.Args, "--addr=http://b.com:566/something.avsc")
    os.Args = append(os.Args, "Get")
    os.Args = append(os.Args, `./some/resource/fred`)

    main()

    // Test results here, and decide pass/fail.
}

【讨论】:

  • 你快到了,因为 main 会得到你的论点。但至少我看到了两个问题。首先它不清楚当您调用main 时会发生什么,因为它因应用程序而异(它会循环或退出),因此这可能不适用于 OP。第二个是你已经替换了os.Args,那么运行的其他测试会发生什么。
猜你喜欢
  • 2015-05-01
  • 1970-01-01
  • 2013-05-08
  • 1970-01-01
  • 1970-01-01
  • 2020-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多