I'm using Go 1.24.3, installed via Homebrew on an Apple M1, running Sequoia 15.5.
I have a main:
//main.go
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
All OK so far (obviously), compiles and runs.
I wanted to test an Example
and added:
//main_test.go
package main
func ExampleMain() {
main()
//Output: Hello, world!
}
This results in
$ go test
# blah/hello
# [blah/hello]
./main_test.go:3:1: ExampleMain refers to unknown identifier: Main
FAIL blah/hello [build failed]
But changing the main.go
as follows works (Note the example is NOT changed, still calls the main()
function,with lower case 'main')
//main.go
package main
import "fmt"
func main() {
Main()
}
func Main() {
fmt.Println("Hello, world!")
}
Running go test
now results in:
go test
PASS
ok blah/hello 0.005s
My understanding is that *_test
files should have access to the internal (lower case) functions of other functions in the same package.
I also understand there is different handling for the main
package, but I cannot see any documentation that the tests should work differently for main
.
Personally, I think this is that the 'ExampleFunction' needs a 'Function' function, regardless before it will compile/run. I'm assuming test (non example) funcitons are named and work the same way ('TestFunction').
In this case how should I name/define tests against internal functions?
Here's the go env
:
$ go env -json GOROOT GOPATH GOBIN GOVERSION GOARCH GOARM64
{
"GOARCH": "arm64",
"GOARM64": "v8.0",
"GOBIN": "",
"GOPATH": "/Users/graham.kelly/prj/golang",
"GOROOT": "/opt/homebrew/Cellar/go/1.24.3/libexec",
"GOVERSION": "go1.24.3"
}
Edit (and comments) based on request from yshavit
Here's the go.mod
contents, the current working directory and it's contents.
$ cat go.mod
module blah/hello
go 1.24.3
$ pwd
/Users/graham.kelly/prj/golang/hello
$ ls -l
total 24
-rw-r--r-- 1 graham.kelly staff 37 28 May 12:28 go.mod
-rw-r--r--@ 1 graham.kelly staff 71 28 May 17:22 main_internal_test.go
-rw-r--r--@ 1 graham.kelly staff 156 28 May 17:37 main.go
AFAIK, the files are top level wrt. the go.mod
, unless there's some nuance I have not extracted from the docs yet.
My sequence was
cd
into itgo mod init blah/hello
main.go
and run it locallyNote obviously this was not the exact sequence. There was fiddling with
git
and my editor, but effectively it was the above.
The Examples documentation says:
The naming convention to declare examples for the package, a function F, a type T and method M on type T are:
func Example() { ... } func ExampleF() { ... } func ExampleT() { ... } func ExampleT_M() { ... }
Multiple example functions for a package/type/function/method may be provided by appending a distinct suffix to the name. The suffix must start with a lower-case letter.
func Example_suffix() { ... } func ExampleF_suffix() { ... } func ExampleT_suffix() { ... } func ExampleT_M_suffix() { ... }
The name ExampleMain
matches the pattern ExampleF
and ExampleT
where F
is the name of an exported function and T
is the name of an exported type.
The go test
command runs the go vet
command. The go vet
command reports an error because the package does not have an exported function or type named Main
.
Fix by associating the example with the package, an exported type, an exported function or an exported method on an exported type
In the following code, the example is associated with the package and has the suffix "jasmine". The suffix "jasmine" can be replaced with any unexported identifier. I chose my name because I am awesome.
package main
func Example_jasmine() {
main()
//Output: Hello, world!
}