Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: Cannot exclude file from tests using +build !test #12120

Closed
slimsag opened this issue Aug 12, 2015 · 8 comments
Closed

cmd/go: Cannot exclude file from tests using +build !test #12120

slimsag opened this issue Aug 12, 2015 · 8 comments

Comments

@slimsag
Copy link

slimsag commented Aug 12, 2015

Under normal circumstances you would place test code into a file matching the test build constraint/tag, e.g. my_test.go. The naming convention of the file has led me to believe that this is a build constraint/tag.

However, it is not possible to exclude some code from being built into tests ran by go test, because writing a file like foo.go:

// +build !test

package foo

...

Will always compile under go test. This is a shame because there are some situations that do warrant different behavior for testing, and this makes it hard to deal with such situations.

@ianlancetaylor ianlancetaylor changed the title Cannot exclude file from tests using +build !test cmd/go: Cannot exclude file from tests using +build !test Aug 12, 2015
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Aug 12, 2015
@dmitshur
Copy link
Contributor

Under normal circumstances you would place test code into a file matching the test build constraint/tag, e.g. my_test.go. The naming convention of the file has led me to believe that this is a build constraint/tag.

It's not a build constrant/tag named test, but rather a filename suffix of _test. Note that my_test.go will be used in tests only, but mytest.go will be included in normal builds too because the filename does not have the underscore of _test. Also, you can't use // +build test or // +build _test, it has to be a _test suffix in the filename.

However, it is not possible to exclude some code from being built into tests ran by go test [via a build tag]

I want to share an opinion related to that. I consider that a feature. I think it's great you (or anyone) can't exclude some .go files from tests. That makes test code purely additive and easier to reason about.

there are some situations that do warrant different behavior for testing,

I think those situations are very rare, and they're best handled as special cases. For example, they can check the binary name for ".test" or ".test.exe" suffix to find out if it's a test running, since Go names the test binaries with a ".test(.exe)" suffix.

From go help test docs:

The test binary, called pkg.test where pkg is the name of the
directory containing the package sources

@mmindenhall
Copy link

It would also be useful to be able to use test as a build tag to only include certain files in the build when testing.

// +build test

A file with such a tag would be included in the build under go test, but excluded under go build or go run.

This tag would enable test data and/or helper functions to be shared across related packages. Currently the only way to share test data/code with another package is to remove the _test suffix, which is of course undesirable because now that code is always included in the build.

Here's a specific example of how this is useful. In my current project I have the following packages:

  • models -- contains my types.
  • store -- handles persistence of model types
  • search -- implements search indexing/retrieval within model types

Within the models package, I now have a testdata_test.go file that contains sample model data and functions to generate random model data. I use this extensively in other tests within the models package. However, even if I capitalize variable names and functions in this file, I can't access them from tests within the store or search package. If I could replace the _test suffix with the test tag, my test data and helpers would be visible in other packages, but only included in test builds.

@minux
Copy link
Member

minux commented Dec 11, 2015 via email

@mmindenhall
Copy link

Here's what I finally resorted to in order to be able to share my test data and helper functions with other packages.

  1. Renamed testdata_test.go to testdata.go (thereby removing from test scope)
  2. Added this build tag to the file: // +build !release
  3. Changed build scripts to build with release tag for distribution

Thus, my test code is always available when I'm testing (and even when I'm not), but doesn't get included in released binaries. This is a hack, but I decided this was a better solution than either:

  1. Unnaturally combining packages for the sake of sharing test data/code; or
  2. Duplicating (and needing to maintain) test data/code across all packages that use it

Supporting test as a build tag would accomplish the same thing more elegantly.

I don't see how your suggestion to create a "separate test helper package" would help. Regardless of whether the code lives in my current models package or a new models_test_helper package, code will only be visible to other packages if exported from .go files instead of _test.go files.

I'm also somewhat skeptical about this being as dangerous as you say. Did you have a specific example in mind of how this could result in "a bug that only happens in tests, or worse, that only happens when the package is not used not in tests"?

@dmitshur
Copy link
Contributor

I don't see how your suggestion to create a "separate test helper package" would help. Regardless of whether the code lives in my current models package or a new models_test_helper package, code will only be visible to other packages if exported from .go files instead of _test.go files.

As I understand the suggestion, the whole point of models_test_helper is that it would be a package completely dedicated to providing common functionality for tests. It would have no other stuff, except what's needed for tests. Everything in it would be in normal .go files. You could put that package under internal to make sure no one else tries to use it.

@mmindenhall
Copy link

Thanks for 'splaining! I read the proposal on internal...that still doesn't help, as I need a solution that includes the code during test, but excludes it on normal builds.

To provide a bit more context, the application I'm working on runs in industrial gateways (specialized wifi routers that also have cellular data capabilities). Some of these devices have as little as 64MB of free RAM and ~80MB flash when we install our binary. Hence we can't afford to bloat the binary with a bunch of dead test code/data.

I'm happy enough with the workaround I described above...just wanted to chime in with another use case for a test build tag.

@dmitshur
Copy link
Contributor

I read the proposal on internal...that still doesn't help

internal is unrelated; it's just to prevent other people from potentially using your package which is meant for internal testing use only.

I need a solution that includes the code during test, but excludes it on normal builds.

That criteria is satisfied, unless I'm mistaken.

To elaborate, suppose you have packages a and b that you want to share some common test-only code between.

So, you'll end up having:

a/
    a.go - Does not import models_test_helper.
    a_test.go - Imports and uses models_test_helper.
b/
    b.go - Does not import models_test_helper.
    b_test.go - Imports and uses models_test_helper.
models_test_helper/
    models_test_helper.go

Packages a and b do not import models_test_helper for normal builds. They only import models_test_helper during tests.

@rsc
Copy link
Contributor

rsc commented Jun 5, 2017

This is working as designed.

@rsc rsc closed this as completed Jun 5, 2017
@golang golang locked and limited conversation to collaborators Jun 5, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants