如何知道我是否在”go test”中运行

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

How do I know I'm running within "go test"

问题

当我运行"go test"时,我想使用一个不同的配置文件。在我的代码中,如何知道我是在测试环境还是正常环境中运行?是否有某种环境变量可以检查?

英文:

When I run "go test", I want to use a different configuration file. How do I know within my code if I'm running within a test context or a normal context? Is there some sort of environment variable to check?

答案1

得分: 56

测试包在加载时会修改全局环境:它会注册很多命令行标志。因此,我们可以检查这些标志是否已注册:

func init() {
	if flag.Lookup("test.v") == nil {
		fmt.Println("正常运行")
	} else {
		fmt.Println("在 go test 下运行")
	}
}
英文:

The testing package modifies the global environment when loaded: it registers a lot of command-line flags. So, we can check if these flags are registered:

func init() {
	if flag.Lookup("test.v") == nil {
		fmt.Println("normal run")
	} else {
		fmt.Println("run under go test")
	}
}

答案2

得分: 38

由于flag.Lookup("test.v")方法对我无效,我想分享我的解决方案:

strings.HasSuffix(os.Args[0], ".test")

或者

strings.Contains(os.Args[0], "/_test/")

这两种方法似乎都可以工作。

英文:

Since the flag.Lookup("test.v") approach does not work for me, I'd like to share my own solution:

strings.HasSuffix(os.Args[0], ".test")

Or

strings.Contains(os.Args[0], "/_test/")

Both seem to work.

答案3

得分: 10

The flag.Lookup("test.v") == nil method seems to work but I would recommend using TestMain, which is specifically designed to allow specific setup and teardown for tests. If you include this method in the package you want to test, it will be called before your individual tests and so you can set a global flag or perform whatever test-specific configuration you want to do before calling m.Run() as follows

func TestMain(m *testing.M) {
    // test context initialization here
    os.Exit(m.Run())
}

PS: this is actually what @calvin-sugianto suggested, except Gin has nothing to do with it

英文:

The flag.Lookup("test.v") == nil method seems to work but I would recommend using TestMain, which is specifically designed to allow specific setup and teardown for tests. If you include this method in the package you want to test, it will be called before your individual tests and so you can set a global flag or perform whatever test-specific configuration you want to do before calling m.Run() as follows

func TestMain(m *testing.M) {
    // test context initialization here
    os.Exit(m.Run())
}

PS: this is actually what @calvin-sugianto suggested, except Gin has nothing to do with it

答案4

得分: 9

一种可能的方法是使用构建约束。如果你运行go test命令如下:

go test -tags testing pkgname

那么你可以使用该标签来选择哪些文件将被包含在标准构建中,哪些文件将用于测试。

如果你将标准配置放在一个单独的文件中,然后在文件顶部添加以下行,将确保它不会用于测试:

// +build !testing

然后你可以在*_test.go文件中或其他需要设置testing标签的文件中包含测试配置。

英文:

One possibility would be to use build constraints. If you run go test as:

go test -tags testing pkgname

Then you can use that tag to select which files will be included in a standard build of your package, and which will be used for testing.

If you put your standard configuration in a file of its own, then adding a line to the top like the following will ensure that it is not used for testing:

// +build !testing

You can then include the testing configuration in one of the *_test.go files, or in some other file that requires that the testing tag be set.

答案5

得分: 8

代码示例会有所帮助。但从你的问题来看,听起来你在某个地方硬编码了一个配置文件的路径,而你可能想要传递它。

修改你正在测试的函数,使其接受一个参数来定义配置文件,然后在测试代码中传递一个不同的路径,而不是在非测试代码中使用的路径。当测试和生产环境中的代码路径不同时,这是一个不好的实践。

英文:

Code examples would help. But from your question it sounds like you've hardcoded a path to a config file somewhere when you probably wanted to pass it in instead.

Change the function you are testing to take a parameter defining the config file and then in your test code pass a different path in than you use in the non test code. It's bad practice for your code to have a different path when testing vs production.

答案6

得分: 6

Go 1.22(2023年第三季度)或Go 1.23(2024年第一季度)可能会提供此功能,考虑到提案“# 5600 testing: add func Testing() bool”已被接受并已实施。请参见CL 475496

> ## testing: add Testing function
>
> Testing函数报告程序是否是由“go test”创建的测试。

使用src/testing/testing.go

// testBinary is set by cmd/go to "1" if this is a binary built by "go test".
// The value is set to "1" by a -X option to cmd/link. We assume that
// because this is possible, the compiler will not optimize testBinary
// into a constant on the basis that it is an unexported package-scope
// variable that is never changed. If the compiler ever starts implementing
// such an optimization, we will need some technique to mark this variable
// as "changed by a cmd/link -X option".
var testBinary = "0"

// Testing reports whether the current code is being run in a test.
// This will report true in programs created by "go test",
// false in programs created by "go build".
func Testing() bool {
	return testBinary == "1"
}

示例

package main
import (
	"fmt"
	"testing"
)
func main() {
	fmt.Println(testing.Testing())
}

func TestTesting(t *testing.T) {
	if !testing.Testing() {
		t.Errorf("testing.Testing() == %t, want %t", testing.Testing(), true)
	}
}

用例示例

> 使用testing.Testing(),我可以轻松地保护非单元测试代码:

> go >// file/that/should/not/be/used/from/testing.go > >func prodEnvironmentData() *Environment { > if testing.Testing() { > log.Fatal("Using production data in unit tests") > } > .... >} >

英文:

> How do I know within my code if I'm running within a test context or a normal context?

Go 1.22 (Q3 2023) or Go 1.23 (Q1 2024) could provide this feature, considering the proposal "# 5600 testing: add func Testing() bool" has been accepted, and is currently implemented.
See CL 475496:

> ## testing: add Testing function
>
> The Testing function reports whether the program is a test created by "go test".

With src/testing/testing.go

// testBinary is set by cmd/go to "1" if this is a binary built by "go test".
// The value is set to "1" by a -X option to cmd/link. We assume that
// because this is possible, the compiler will not optimize testBinary
// into a constant on the basis that it is an unexported package-scope
// variable that is never changed. If the compiler ever starts implementing
// such an optimization, we will need some technique to mark this variable
// as "changed by a cmd/link -X option".
var testBinary = "0"

// Testing reports whether the current code is being run in a test.
// This will report true in programs created by "go test",
// false in programs created by "go build".
func Testing() bool {
	return testBinary == "1"
}

Example:

package main
import (
	"fmt"
	"testing"
)
func main() {
	fmt.Println(testing.Testing())
}

func TestTesting(t *testing.T) {
	if !testing.Testing() {
		t.Errorf("testing.Testing() == %t, want %t", testing.Testing(), true)
	}
}

Use case example:

> With testing.Testing() I can easily guard non-unit-tests code with:
>
>go
>// file/that/should/not/be/used/from/testing.go
>
>func prodEnvironmentData() *Environment {
> if testing.Testing() {
> log.Fatal("Using production data in unit tests")
> }
> ....
>}
>

答案7

得分: 5

我是新手学习golang,flag.Lookup("test.v")对我没有起作用,所以我找到了一种方法来识别上下文是测试还是正常的,通过在init()函数中设置环境变量。

如果你有一个测试文件,例如abc.text.go,在init()函数中将环境变量"GO_ENV"设置为"testing"。

func init() {
	os.Setenv("GO_ENV", "testing")
}

然后在任何你想要知道上下文的地方使用os.Getenv("GO_ENV")。
abc.go

if os.Getenv("GO_ENV") == "testing" {

} else {

}
英文:

I am new to golang and flag.Lookup("test.v") did not work for me, So i have found way to identify if context is testing or normal by setting ENV variable in init().

If you have test file for example abc.text.go, set env variable "GO_ENV" to testing in init().

func init() {
	os.Setenv("GO_ENV", "testing")
}

And where ever you want to know the context use os.Getenv("GO_ENV")
abc.go

if os.Getenv("GO_ENV") == "testing" {

} else {

}

答案8

得分: 3

The flag.Lookup("test.v") solution does not work for me either (go 1.13), and I have lots of services to maintain and it is not feasible to use the func TestMain(m *testing.M) solution in every service. As all the services share a common library, I've come up with the following solution:

func isInTests() bool {
    for _, arg := range os.Args {
        if strings.HasPrefix(arg, "-test.v=") {
            return true
        }
    }
    return false
}

This is similar to the flag.Lookup("test.v") solution because we check if -test.v is present.

EDIT: updated the code based on @mh-cbon comment

英文:

The flag.Lookup("test.v") solution does not work for me either (go 1.13), and I have lots of services to maintain and it is not feasible to use the func TestMain(m *testing.M) solution in every service. As all the services share a common library, I've come up with the following solution:

func isInTests() bool {
    for _, arg := range os.Args {
        if strings.HasPrefix(arg, "-test.v=") {
            return true
        }
    }
    return false
}

This is similar to the flag.Lookup("test.v") solution because we check if -test.v is present.

EDIT: updated the code based on @mh-cbon comment

答案9

得分: 1

类似于Pram的答案,当你运行测试时,我可能会设置一个环境变量。

Makefile

test:
 ENV=testing go test ./...

main.go

  env := os.Getenv("ENV")
英文:

Similar to Pram's answer I might set an environment variable when you run the tests.

Makefile

test:
 ENV=testing go test ./...

main.go

  env := os.Getenv("ENV")

答案10

得分: 0

如果您想检测文件是通过"go run"运行还是作为可执行文件运行,此函数将检查目录是否包含"/Temp/go-build"(还会检查Windows支持的"")

如果 strings.Index(os.Args[0], "/Temp/go-build") != -1 || strings.Index(os.Args[0], "\\Temp\\go-build") != -1 {
    // 通过go run运行
} else {
    // 作为可执行文件运行
}
英文:

If your trying to detect if the file is being run through "go run" vs an executable, this function checks if the directory contains "/Temp/go-build" (also checks for \ for windows support)

if strings.Index(os.Args[0], "/Temp/go-build") != -1 || strings.Index(os.Args[0], "\\Temp\\go-build") != -1 {
    // ran with go run
} else {
    // ran as executable file
}

答案11

得分: 0

A different approach will be using a seperate init() func in test file per package.

Since *_test.go runs only during 'go test' we could

feature/feature_setup_test.go

package feature

fun init() {  
       fmt.Println("Code For Test initialization")
}

This init() func from test is called only during testing; Unlike an init() func from feature.go which will with every import/run.

And one more thing when we do testing, init() in test will get executed only after non-test init() function.

*So you can override the a feature.go -> init() with feature_test.go -> init().

Sample code available in gist.

英文:

A different approach will be using a seperate init() func in test file per package.

Since *_test.go runs only during 'go test' we could

feature/feature_setup_test.go

package feature

fun init() {  
       fmt.Println("Code For Test initialization")
}

This init() func from test is called only during testing; Unlike an init() func from feature.go which will with every import/run.

And one more thing when we do testing, init() in test will get executed only after non-test init() function.

So you can override the a feature.go -> init() with feature_test.go -> init().

Sample code available in gist.

答案12

得分: 0

检查堆栈中是否存在_test.go

package utils

import (
	"runtime/debug"
	"strings"
)

func IsInTest() bool {
	stacks := strings.Split(string(debug.Stack()), "\n")
	for _, line := range stacks {
		if strings.HasPrefix(line, "\t") {
			path := strings.Split(strings.TrimSpace(line), ":")[0]
			if strings.HasSuffix(path, "_test.go") {
				return true
			}
		}
	}
	return false
}
英文:

Check if _test.go exist in stack.

package utils

import (
	"runtime/debug"
	"strings"
)

func IsInTest() bool {
	stacks := strings.Split(string(debug.Stack()), "\n")
	for _, line := range stacks {
		if strings.HasPrefix(line, "\t") {
			path := strings.Split(strings.TrimSpace(line), ":")[0]
			if strings.HasSuffix(path, "_test.go") {
				return true
			}
		}
	}
	return false
}

答案13

得分: -1

更健壮的解决方案是:

 func init() {
    if v := flag.Lookup("test.v"); v == nil || v.Value.String() != "true" {
        fmt.Println("正常运行")
    } else {
        fmt.Println("在 go test 下运行")
    }
 }
英文:

More robust solution that Garrett's one is:

 func init() {
    if v := flag.Lookup("test.v"); v == nil || v.Value.String() != "true" {
        fmt.Println("normal run")
    } else {
        fmt.Println("run under go test")
    }
 }

huangapple
  • 本文由 发表于 2013年1月10日 09:05:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/14249217.html
匿名

发表评论

匿名网友

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

确定