165

I have seen several different test package naming strategies within Go and wanted to know what pros and cons of each are and which one I should use.

Strategy 1:

File name: github.com/user/myfunc.go

package myfunc

Test file name: github.com/user/myfunc_test.go

package myfunc

See bzip2 for an example.

Strategy 2:

File name: github.com/user/myfunc.go

package myfunc

Test file name: github.com/user/myfunc_test.go

package myfunc_test

import (
    "github.com/user/myfunc"
)

See wire for an example.

Strategy 3:

File name: github.com/user/myfunc.go

package myfunc

Test file name: github.com/user/myfunc_test.go

package myfunc_test

import (
    . "myfunc"
)

See strings for an example.

The Go standard library seems to use a mixture of strategy 1 and 2. Which of all three should I use? It's a pain appending package *_test to my testing packages as it means I can't test my package private methods but maybe there is a hidden advantage I am not aware of?

Amin Shojaei
  • 5,451
  • 2
  • 38
  • 46
Dan
  • 5,013
  • 5
  • 33
  • 59
  • 12
    This question is only going to result in varying opinions, but I'll throw in mine. You shouldn't need to test your private methods. You want to test the interface of your package that other developers will consume. If the tests fail then you know your private methods need a look. – Brenden Nov 15 '13 at 18:42
  • 2
    The [wire]( https://github.com/btcsuite/btcd/blob/master/wire/msgtx_test.go) example for Strategy 2, is actually now also an example of Strategy 1... – durp Dec 06 '17 at 19:17

4 Answers4

225

The fundamental difference between the three strategies you've listed is whether or not the test code is in the same package as the code under test. The decision to use package myfunc or package myfunc_test in the test file depends on whether you want to perform white-box or black-box testing.

There's nothing wrong with using both methods in a project. For instance, you could have myfunc_whitebox_test.go and myfunx_blackbox_test.go.

Test Code Package Comparison

  • Black-box Testing: Use package myfunc_test, which will ensure you're only using the exported identifiers.
  • White-box Testing: Use package myfunc so that you have access to the non-exported identifiers. Good for unit tests that require access to non-exported variables, functions, and methods.

Comparison of Strategies Listed in Question

  • Strategy 1: The file myfunc_test.go uses package myfunc — In this case the test code in myfunc_test.go will be in the same package as the code being tested in myfunc.go, which is myfunc in this example.
  • Strategy 2: The file myfunc_test.go uses package myfunc_test — In this case the test code in myfunc_test.go "will be compiled as a separate package, and then linked and run with the main test binary." [Source: Lines 58–59 in the test.go source code]
  • Strategy 3: The file myfunc_test.go uses package myfunc_test but imports myfunc using the dot notation — This is a variant of Strategy 2, but uses the dot notation to import myfunc.
Matthew Rankin
  • 457,139
  • 39
  • 126
  • 163
  • 2
    It should be noted that using Strategy 1 will also keep files with `_test.go` separate than the package being tested (the same behavior as Strategy 2). This doesn't seem to be documented per https://github.com/golang/go/issues/15315 – Kevin Deenanauth May 09 '16 at 17:26
  • I saw strong package use Strategy 3, but I can't understand what's the point? – PickBoy Apr 28 '19 at 07:54
  • 2
    I forked a package and made changes, and now my tests are all trying to import the original repo instead of my forked package. With Strategy 3, I don't have to change the "github.com/original/link" to "github.com/my/fork", because it's just referencing '.' instead. – nmarley Apr 30 '19 at 18:06
  • 1
    @KevinDeenanauth This just surprised me. I thought I had found a pitfall when I just found a `_test.go` with a non-`_test` package name containing a `func init()` which changes some global package variable for testing. I was wrong. – Zyl May 10 '19 at 13:30
  • 1
    @nmarley the `.` doesn't resolve your fork issue. It's not a relative import. It justs imports the identifiers "into the current package". – qaisjp Sep 15 '19 at 01:42
25

It depends on the scope of your tests. High level tests (integration, acceptance, etc...) should probably be placed in a separate package to ensure that you are using the package via the exported API.

If you have a large package with a lot of internals that need to be put under test then use the same package for your tests. But that's not an invitation for your tests to access any bit of private state. That would make refactoring a nightmare. When I write structs in go I am often implementing interfaces. It is those interface methods that I invoke from my tests, not all of the helper methods/functions individually.

Michael Whatcott
  • 5,603
  • 6
  • 36
  • 50
13

You should use strategy 1 whenever possible. You can use the special foo_test package name to avoid import cycles, but that's mostly there so the standard library can be tested with the same mechanism. For example, strings cannot be tested with strategy 1 since the testing package depends on strings. As you said, with strategy 2 or 3 you don't have access to the package's private identifiers, so it's usually better to not use it unless you have to.

guelfey
  • 1,316
  • 10
  • 5
4

One important notes I'd like to add about import . from Golang CodeReviewComments:

The import . form can be useful in tests that, due to circular dependencies, cannot be made part of the package being tested:

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

In this case, the test file cannot be in package foo because it uses bar/testutil, which imports foo. So we use the 'import .' form to let the file pretend to be part of package foo even though it is not.

Except for this one case, do not use import . in your programs. It makes the programs much harder to read because it is unclear whether a name like Quux is a top-level identifier in the current package or in an imported package.

Eric
  • 295
  • 3
  • 6