Do you export a function just so that you can unit test it?

I have a public function F in my package, which first calls GetX then calls FilterY, then return the filtered results.

Both GetX and FilterY are public, as I want thorough unit tests for them. But, they serve no purpose, they are unlikely to be called alone by any users of my package. Only F is going to be called, thus making GetX and FilterY good candidates for private functions.

Should I keep these 2 methods public just for the sake of unit tests ? Bear in mind there is some complex logic in FilterY so it needs a lot of unit test cases.

If your *_test.go files for the package are in the same directory with the package source code then they are part of the package itself, and they can access all functions defined in the package whether public or private. Look at the go packages themselves in go/src.

Are you giving advice without trying it first ? That is the first thing I have tried and it does not work.

It works, though you can not use package foo_test then, but have to use the same name for the package as the package under test.

1 Like

You mean placing the tests in the same package as the code. This looks like a bad idea long term, as I do not want the importers of my package unknowingly import any sqlmock or whatever else I import solely for testing.

A *_test.go, even though if it is in the same package as the tested function, will not be part of your deliverable.

https://golang.org/cmd/go/#hdr-Compile_packages_and_dependencies

When compiling packages, build ignores files that end in ‘_test.go’.

I call BS on this. Namely I have a file a.go and a_test.go, both of them having the first line package mypackage. If I define a non test function inside a_test.go, I am allowed to call it from a.go.

I therefore doubt then that it will not import the whole imported packages from a_test.go, every time I import mypackage.

No bullshit… For me the following program does not compile, as printer is not available.

$ cat main.go
package main

import "./foo"

func main() {
        foo.Print()
}
$ cat foo/print.go
package foo

func Print() {
        printer()
}
$ cat foo/print_test.go
package foo

import "fmt"

func printer() {
        fmt.Println("Foo")
}
$ go run main.go
# _/tmp/tmp.zQApmyskok/foo
foo/print.go:4:2: undefined: printer

So call it as you want, until you have proven that a function from a _test.go file leaks, I trust in the documentation. And if you can indeed prove that there is a leak, then its worth a bug report, such that either the compiler or the documentation can be fixed.

When the package is compiled to its .a file for linking _test.go files are ignored. Look at the regexp package in the go src directory: https://golang.org/src/regexp/.

Hi @clbanning and @NobbZ,

This is a very strange situation. I am using visual studio code and go 1.14:
file a.go:

package a

func example() {
   printSomething()
}

file a_test.go:

package a

import "fmt"

func printSomething() {
    fmt.Println("something")
}

This works just fine, no compile errors. What is happening here ? I have even ran a test, it does print.

No compile errors when you do what?

If I copy your files and try to compile them, it fails:

$ go build .
# _/tmp/tmp.Z4s5MMdPvS
./a.go:4:4: undefined: printSomething

And for the sake of completeness and comparability:

$ go version
go version go1.14.6 linux/amd64

This behaviour is reproducible from go 1.12 through 1.15:

$ for i in 12 13 14; do nix run nixos.go_1_$i -c go version; nix run nixos.go_1_$i -c go build .; done
go version go1.12.17 linux/amd64
# _/tmp/tmp.Z4s5MMdPvS
./a.go:4:4: undefined: printSomething
go version go1.13.12 linux/amd64
# _/tmp/tmp.Z4s5MMdPvS
./a.go:4:4: undefined: printSomething
go version go1.14.4 linux/amd64
# _/tmp/tmp.Z4s5MMdPvS
./a.go:4:4: undefined: printSomething
$ nix run nixpkgs.go_1_15 -c go version; nix run nixpkgs.go_1_15 -c go build .
go version go1.15beta1 linux/amd64
# _/tmp/tmp.Z4s5MMdPvS
./a.go:4:4: undefined: printSomething
1 Like

I am running on a macOS computer, could this be it ?

go version
go version go1.15 darwin/amd64

Shouldn’t make a difference, but have you tried to actually build the code using the compiler or did you just trust in your IDE not complaining?

Also, compiling the program above in “test mode” would actually be possible, as tests weren’t possible if you would ignore test files then as well…

1 Like

Just writing to confirm what @NobbZ

Anything ending in _test is ignored at build time

❯ cat a.go
package main

func main() {
  printSomething()
}
❯ cat a_test.go
package main

import "fmt"

func printSomething() {
  fmt.Println("something")
}

Attempt to compile… Correctly can’t call printSomething from main() because is part of an _test file.

❯ go build .
# _/tmp/glb
./a.go:4:3: undefined: printSomething

Just rename a_test.go to ab.go and it will compile just fine - no error is thrown.

❯ mv a_test.go ab.go
❯ go build .