Testing os.Exit scenarios in Go with coverage information (coveralls.io/Goveralls)

前端 未结 3 1870
故里飘歌
故里飘歌 2020-12-03 03:27

This question: How to test os.exit scenarios in Go (and the highest voted answer therein) sets out how to test os.Exit() scenarios within go. As os.Exit()

3条回答
  •  一整个雨季
    2020-12-03 04:16

    With a slight refactoring, you may easily achieve 100% coverage.

    foo/bar.go:

    package foo
    
    import (
        "fmt"
        "os"
    )
    
    var osExit = os.Exit
    
    func Crasher() {
        fmt.Println("Going down in flames!")
        osExit(1)
    }
    

    And the testing code: foo/bar_test.go:

    package foo
    
    import "testing"
    
    func TestCrasher(t *testing.T) {
        // Save current function and restore at the end:
        oldOsExit := osExit
        defer func() { osExit = oldOsExit }()
    
        var got int
        myExit := func(code int) {
            got = code
        }
    
        osExit = myExit
        Crasher()
        if exp := 1; got != exp {
            t.Errorf("Expected exit code: %d, got: %d", exp, got)
        }
    }
    

    Running go test -cover:

    Going down in flames!
    PASS
    coverage: 100.0% of statements
    ok      foo        0.002s
    

    Yes, you might say this works if os.Exit() is called explicitly, but what if os.Exit() is called by someone else, e.g. log.Fatalf()?

    The same technique works there too, you just have to switch log.Fatalf() instead of os.Exit(), e.g.:

    Relevant part of foo/bar.go:

    var logFatalf = log.Fatalf
    
    func Crasher() {
        fmt.Println("Going down in flames!")
        logFatalf("Exiting with code: %d", 1)
    }
    

    And the testing code: TestCrasher() in foo/bar_test.go:

    func TestCrasher(t *testing.T) {
        // Save current function and restore at the end:
        oldLogFatalf := logFatalf
        defer func() { logFatalf = oldLogFatalf }()
    
        var gotFormat string
        var gotV []interface{}
        myFatalf := func(format string, v ...interface{}) {
            gotFormat, gotV = format, v
        }
    
        logFatalf = myFatalf
        Crasher()
        expFormat, expV := "Exiting with code: %d", []interface{}{1}
        if gotFormat != expFormat || !reflect.DeepEqual(gotV, expV) {
            t.Error("Something went wrong")
        }
    }
    

    Running go test -cover:

    Going down in flames!
    PASS
    coverage: 100.0% of statements
    ok      foo     0.002s
    

提交回复
热议问题