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()
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