Testing unexported methods in Go

Today’s post will be a short one. So, I recently came across a cool-but-not-immediately-obvious-for-me fact in Go. You can see it here in the form of a #golang pop quiz tweet.

It was brought to my attention my Emmanuel when he was reviewing a CL for the Go language. At the time I was wondering how to continue testing an unexported method when moving a package tests from package p to package p_test.

I didn’t really want to resort to linknames, and I didn’t think that exporting it was a good solution either. So, he just commented

We can create a fresh file “export_test.go” in which you export such symbols, given that they can ONLY be used in _test.go files

🤯

So it seems that Go will NOT export symbols from test files, as I’d expected. (as they start with a capital letter and belong in the same package!)

So here’s how this deals with the problem described above, and allows to keep having access to methods, constants, or other test data.

-- p.go --
package p

type T struct {}

func unexportedFunc() {}
func (t T) unexportedMethod() {}

-- export_test.go --
package p
func UnexportedFuncForTest() {
    return unexportedFunc()
}
func UnexportedMethodForTest(t) {
    return t.unexportedMethod()
}

-- p_test.go --
package p_test

import . "p"

UnexportedFuncForTest()
foo := T{}
UnexportedMethodForTest(foo)

See you around!

Written on April 17, 2021