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?
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")
}
}
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.
flag.Lookup("test.v")
approach used to work, now it doesn't (I'm using 1.8.1). –
Martin strings.HasSuffix(os.Args[0], ".test")
is more reliable for me. There is one development machine where strings.Contains(os.Args[0], "/_test/")
failed. –
Parsonage flag.Lookup("test.v")
did not. In fact, when I looked at the flag.formal
map (which is what is indexed by flag.Lookup
), there were no flags at all. –
Kazan .test
extension using the -o
flag. FWIW the flag.Lookup("test.v")
method appears to work in 1.18. –
Pardue TestMain
. However, this approach helped me for preparing/setting-up Example*_*
functions in the test. It was useful to simplify the example and focus on showing how to use the functions/methods. Without using extra code like mocking just for the examples. –
Haber 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
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.
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.
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 {
}
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
if strings.HasPrefix(arg, "-test.") {
. Your code won't catch running test is the -v flag is set to false. –
Aubine 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")
Since Go v1.21, you can use testing.Testing()
(docs: https://go.dev/doc/#Testing)
import (
"fmt"
"testing"
)
func main() {
if testing.Testing() {
fmt.Println("We are testing")
} else {
fmt.Println("We are NOT testing")
}
}
(See it in action - Go Playground: https://go.dev/play/p/F3oMiPoPBHm)
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
}
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().
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")
}
}
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
}
© 2022 - 2024 — McMap. All rights reserved.
testing.Testing()
- added in Go v1.21 works fine for me (see pkg.go.dev/testing#Testing) – Tufa