Description
Tests often verify behavior that rely on environment variables. Unfortunately, people often don't realize that setting environment variables in tests using os.Setenv
will set those variables for the entire lifetime of the process. Things get even more complicated when tests are executed in parallel.
As a result, tests either fail when they shouldn't or worse: don't fail when they should.
In the first scenario (failing test), debugging the test probably leads people to the above conclusion, resulting in a code like this:
func TestSomething(t *testing.T) {
os.Setenv("KEY", "VALUE")
defer os.Unsetenv("ENV")
}
It's not necessarily bad, since it's explicit, but it doesn't handle errors and with multiple env vars it would be a lot of unnecessary copy-pasting of boilerplate code.
In the second scenario, it's quite easy to introduce and leave bugs in the code (I've just fixed one today).
I propose adding a Setenv
method to testing.TB, *testing.T, and *testing.B something like this:
// Setenv sets an environment variable for the lifetime of the test.
// It also disables running this test in parallel with other tests.
// The environment variable is automatically cleaned up when the test exits.
func (t *T) Setenv(key string, value string) {
if t.isParallel {
panic("Setenv: test cannot be run in parallel with others")
}
t.disableParallel = true
err := os.Setenv(key, value)
if err != nil {
t.Fatalf("Setenv: %v", err)
}
t.Cleanup(func() {
os.Unsetenv(key)
})
}