How to test code that exits your program in Golang

Sartaj Singh
2 min readApr 25, 2018

Many a times in Golang you write a line of code which logs and exits the program. Some would argue that this results in ungraceful shutdown of your app but what puzzled me was how would I test such methods or lines of code that exit my test suite itself. Turns out you can easily do this by spawning a subprocess and letting that exit while having control over the main thread.

Let’s say, you have a config without which you don’t want your application to start and you write something like this:

package configimport (
"log"
"os"
)
func getConfig(key string) string {
val := os.Getenv(key)

if val == "" {
log.Fatalf("Exiting") // Exits the program
}
return val
}

In the above code, logFatalf() will result in os.Exit(1) and cause the program to exit. Now to test this you can spawn a subprocess to run this part of code as explained below.

package configimport (
"os"
"os/exec"
"testing"

"github.com/stretchr/testify/assert"
)
func TestGetConfig(t *testing.T) {
// Run the crashing code when FLAG is set
if os.Getenv("FLAG") == "1" {
getConfig("KEY")
return
}
// Run the test in a subprocess
cmd := exec.Command(os.Args[0], "-test.run=TestGetConfig")
cmd.Env = append(os.Environ(), "FLAG=1")
err := cmd.Run()

// Cast the error as *exec.ExitError and compare the result
e, ok := err.(*exec.ExitError)
expectedErrorString := "exit status 1"
assert.Equal(t, true, ok)
assert.Equal(t, expectedErrorString, e.Error())
}

Definitely, the above code can be improved, an interesting thing to test would be if we can do the same using Go-routines and channels instead of a subprocess, give it a try?

--

--