如何在Go中测试os.exit场景

mbr*_*ort 29 testing exit-code go

鉴于此代码

func doomed() {
  os.Exit(1)
}
Run Code Online (Sandbox Code Playgroud)

如何正确测试调用此函数将导致存在使用go test?这需要在一组测试中发生,换句话说,os.Exit()调用不会影响其他测试并且应该被捕获.

Tim*_*ann 38

有一个演示文稿由Andrew Gerrand(围棋队的核心成员之一),他展示了如何做到这一点.

给定一个函数(in main.go)

package main

import (
    "fmt"
    "os"
)

func Crasher() {
    fmt.Println("Going down in flames!")
    os.Exit(1)
}
Run Code Online (Sandbox Code Playgroud)

这是你如何测试它(通过main_test.go):

package main

import (
    "os"
    "os/exec"
    "testing"
)

func TestCrasher(t *testing.T) {
    if os.Getenv("BE_CRASHER") == "1" {
        Crasher()
        return
    }
    cmd := exec.Command(os.Args[0], "-test.run=TestCrasher")
    cmd.Env = append(os.Environ(), "BE_CRASHER=1")
    err := cmd.Run()
    if e, ok := err.(*exec.ExitError); ok && !e.Success() {
        return
    }
    t.Fatalf("process ran with err %v, want exit status 1", err)
}
Run Code Online (Sandbox Code Playgroud)

代码所做的是go test在一个单独的进程中再次调用exec.Command,限制执行到TestCrasher测试(通过-test.run=TestCrasher交换机).它还通过BE_CRASHER=1第二次调用检查的环境变量()传递一个标志,如果设置,则调用被测系统,之后立即返回以防止进入无限循环.因此,我们将被退回到我们的原始呼叫站点,现在可以验证实际的退出代码.

来源:安德鲁的演讲第23页.第二张幻灯片还包含演示文稿视频的链接.他在47:09讨论了子过程测试

  • 此方法不能让-cover显示您已测试过的行 (2认同)

All*_*uce 10

我通过使用bouk/monkey来做到这一点:

func TestDoomed(t *testing.T) {
  fakeExit := func(int) {
    panic("os.Exit called")      
  }
  patch := monkey.Patch(os.Exit, fakeExit)
  defer patch.Unpatch()
  assert.PanicsWithValue(t, "os.Exit called", doomed, "os.Exit was not called")
}
Run Code Online (Sandbox Code Playgroud)

猴子在这类工作,以及故障注入和其他困难任务方面都是超级强大的.它确实有一些警告.

  • 作为参考,bouk/monkey 的许可证可能与您的项目不兼容:https://github.com/bouk/monkey/pull/18 (5认同)

Mat*_*elf 7

我不认为你可以在os.Exit不模拟外部(使用exec.Command)过程的测试的情况下测试实际情况.

也就是说,您可以通过创建接口或函数类型来实现目标,然后在测试中使用noop实现:

去游乐场

package main

import "os"
import "fmt"

type exiter func (code int)

func main() {
    doExit(func(code int){})
    fmt.Println("got here")
    doExit(func(code int){ os.Exit(code)})
}

func doExit(exit exiter) {
    exit(1)
}
Run Code Online (Sandbox Code Playgroud)

  • 你也可以添加测试吗? (5认同)

One*_*One 3

你不能,你必须使用exec.Command并测试返回的值。