如何在Go中测试退出代码,而不在退出代码不等于0时退出测试用例。

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

How to test for exit codes in go without exiting the testcase when the exit code is != 0

问题

我正在尝试为一个返回非零退出码的函数编写 Go 单元测试。我正在使用 cobra 开发一个 CLI 应用程序来验证语义版本。如果验证失败,我会返回一些 JSON 信息,并使用 os.Exit(1) 退出。

现在我想测试一下这个函数是否按预期工作。在我的测试中,我传入了一个应该成功并返回 0 的数据集,以及一个应该失败并返回 1 的数据集。但是应该返回 1 的测试总是取消测试,并因此取消所有后续迭代。这是我的代码:

func Test_ShouldGetCorrectExitCode(t *testing.T) {
    testCases := []struct {
        args          []string
        shouldBeValid bool
    }{
        {[]string{"0.1.0"}, false},
        {[]string{"v0.1.0"}, true},
    }
    for _, tc := range testCases {
        assert := assert.New(t)

        cmd := NewCmdValidate()
        cmd.SetArgs(tc.args)
        err := cmd.Execute()

        assert.Nil(err)
    }
}

到目前为止,断言并不是很复杂,因为我无法按照预期运行测试。有人有什么想法,我如何在 Go 中测试退出码吗?

英文:

I'm trying to write a unit test in go for a function that returns non-zero exit codes. I'm developing a CLI app with cobra to validate semantic versions. In case a validation fails, I return some information in JSON and exit with os.Exit(1).

Now I want to test if this really works as intended. In my test I pass with one data set that should success and return 0 and one that should fail and return 1. But the test that should return 1 always cancels the test and hence cancels all following iterations. This is my code:

func Test_ShouldGetCorrectExitCode(t *testing.T) {
	testCases := []struct {
		args          []string
		shouldBeValid bool
	}{
		{[]string{"0.1.0"}, false},
		{[]string{"v0.1.0"}, true},
	}
	for _, tc := range testCases {
		assert := assert.New(t)

		cmd := NewCmdValidate()
		cmd.SetArgs(tc.args)
		err := cmd.Execute()

		assert.Nil(err)
	}
}

So far the assertions are not really sophisticated because I don't get the test to run the way I expect. Anyone got an idea how I can test for exit codes in go?

答案1

得分: 4

最好的解决方案是在你的被测试函数中不要调用os.Exit。一个好的实践是只在main()函数中调用os.Exit,而是让你的函数返回一个退出状态,这样你可以轻松地进行测试。示例代码如下:

func main() {
    os.Exit(run())
}

func run() int {
  /* 在这里进行测试的操作 */
}

然后在你的测试函数中:

func TestRun(t *testing.T) {
    t.Run("应该成功", func(t *testing.T) {
        status := run()
        if status != 0 {
            t.Errorf("意外的退出状态:%d", status)
    })
    t.Run("应该失败", func(t *testing.T) {
        status := run()
        if status != 1 {
            t.Errorf("意外的状态码:%d", status)
        }
    })
}
英文:

The best solution is to not call os.Exit from your function under test. A good practice can be to only call os.Exit from main(), and instead have your function return an exit status, which you can easily test for. Example:

func main() {
    os.Exit(run())
}

func run() int {
  /* Things to test here */
}

Then in your test:

func TestRun(t *testing.T) {
    t.Run("should succeed", func(t *testing.T) {
        status := run()
        if status != 0 {
            t.Errorf("Unexpected exit status: %d", status)
    })
    t.Run("should fail", func(t *testing.T) {
        status := run()
        if status != 1 {
            t.Errorf("Unexpected status code: %d", status)
        }
    })
}

huangapple
  • 本文由 发表于 2023年8月8日 20:31:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76859593.html
匿名

发表评论

匿名网友

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

确定