'"flag provided but not defined" error in Go test despite the flag being defined in init()?

This question is similar to go test flag: flag provided but not defined, but since that question does not contain a minimal example and the answer is quite high-level, I'm asking it again. In a Go module with a main.go and a main_test.go,

.
├── go.mod
├── go.sum
├── main.go
└── main_test.go

The main.go defines a sayHi flag:

package main

import (
    "flag"
    "fmt"
)

var sayHi bool

func init() {
    flag.BoolVar(&sayHi, "sayHi", false, "Say hi or not")
    flag.Parse()
}

func main() {
    if sayHi {
        fmt.Println("Hi!")
    }
}

and the main_test.go is just a placeholder test:

package main

import "testing"

func TestSayHi(t *testing.T) {

}

The problem is that if I try to run the tests, I get a "flag provided but not defined" error:

> go test ./...
flag provided but not defined: -test.testlogfile
Usage of /var/folders/tp/s7nwwdws1wj0z8s0vftppnnc0000gn/T/go-build952058535/b001/my-module.test:
  -sayHi
        Say hi or not
FAIL    github.com/kurtpeek/my-module   0.192s
FAIL

From the answer of the aforementioned question,

You have to make sure that all flag definitions happen before calling flag.Parse(), usually by defining all flags inside init() functions.

I don't see how that is not being done here?

go


Solution 1:[1]

Create test binary with following command and then execute it with your argument.

> go test -c -o test
./test --sayHi=true
PASS

go test command does not pass along the arguments to underlying tests.

Solution 2:[2]

Update as of May 2022 - NOT fixed

So far the recommended approach is to move flag initalisation outside of init() (so stupid, I know!)

So I did that:

  • moving the code for flag handling to its own function,
  • and then calling that function at the top of main()

and my tests stopped complaining.

func initParseCommandLineFlags() {
   // do your flag thing here
}

func main() {
    initParseCommandLineFlags()
    ...
}

NOTE: A huge down side was that I had to move all of my initialisation out of init() into other setup functions, because my program startup can be modified by command line switches.

So I don't have init anymore :(

Reference: https://github.com/golang/go/issues/46869#issuecomment-865695953

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Abhimanyu Gite
Solution 2 Raider of the lost BBS