在执行测试套件期间设置特定的环境变量。

huangapple go评论72阅读模式
英文:

Set particular environment variables during execution of a test suite

问题

我想在Go中运行一个与环境变量有关的单元测试函数。

在某个时候,我会这样写(不是故意的):

	for test := range tests {
		for k, v := range test.envVars {
			os.Setenv(k, v)
		}

有没有办法确保在测试执行期间,通过对上述os.Setenv()调用设置的变量将是测试函数可用的唯一环境变量

英文:

I want to run a unit test fxn in Go which has to do with env vars.

At some point I go (no pun intended)

	for test := range tests {
		for k, v := range test.envVars {
			os.Setenv(k, v)
		}

Is there a way to make sure that during the test execution, the variables set by the call to os.Setenv() above will be the only env vars available to the test function?

答案1

得分: 4

你可以使用os.Environ获取当前的环境变量,并使用os.Unsetenv来取消设置。

假设在测试完成后你需要恢复这些变量,你可以使用subtest(*testing.T).Cleanup来为每个环境创建一个子测试(https://play.golang.org/p/A5HGZwWm-NS):

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			// 注意:在这个子测试或其父测试中不要调用t.Parallel,
			// 否则环境将会被破坏。
			//
			// (但是,t的子测试可以并行运行。)

			prevEnv := os.Environ()
			for _, entry := range prevEnv {
				parts := strings.SplitN(entry, "=", 2)
				os.Unsetenv(parts[0])
			}
			for k, v := range tc.envVars {
				os.Setenv(k, v)
			}
			t.Cleanup(func() {
				for k := range tc.envVars {
					os.Unsetenv(k)
				}
				for _, entry := range prevEnv {
					parts := strings.SplitN(entry, "=", 2)
					os.Setenv(parts[0], parts[1])
				}
			})

			
		})
	}

另外请注意,Go 1.17 添加了(*testing.T).Setenv方法,它可以自动清理修改的环境变量。然而,目前还没有相应的(*testing.T).Unsetenv方法。


如果你想要能够并行运行测试,你可以使用os/exec-test.run标志来将特定的子测试重新执行为主测试进程的子进程,每个子进程都有自己独立的环境。

英文:

You can use os.Environ to obtain the current environment and os.Unsetenv to unset it.

Presumably you would also need to restore those variables after the test completes, for which you could use a subtest per environment with (*testing.T).Cleanup (https://play.golang.org/p/A5HGZwWm-NS):

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			// NOTE: do NOT call t.Parallel in this subtest or its parent,
			// or the environment WILL be corrupted.
			//
			// (However, *subtests of* t may be run in parallel.)

			prevEnv := os.Environ()
			for _, entry := range prevEnv {
				parts := strings.SplitN(entry, "=", 2)
				os.Unsetenv(parts[0])
			}
			for k, v := range tc.envVars {
				os.Setenv(k, v)
			}
			t.Cleanup(func() {
				for k := range tc.envVars {
					os.Unsetenv(k)
				}
				for _, entry := range prevEnv {
					parts := strings.SplitN(entry, "=", 2)
					os.Setenv(parts[0], parts[1])
				}
			})

			
		})
	}

Also note that Go 1.17 adds the (*testing.T).Setenv method, which cleans up the modification automatically. However, there is not yet a corresponding (*testing.T).Unsetenv.


If you want to be able to run tests in parallel, you could instead use subtests with os/exec and the -test.run flag to re-exec the particular subtest as a subprocess of the main test process, with its own distinct environment.

huangapple
  • 本文由 发表于 2021年8月7日 02:19:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/68686006.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定