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: Test helper code not found #32379

Closed
kstenerud opened this issue Jun 1, 2019 · 10 comments
Closed

cmd/go: Test helper code not found #32379

kstenerud opened this issue Jun 1, 2019 · 10 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@kstenerud
Copy link

What version of Go are you using (go version)?

$ go version
go version go1.12.5 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/karl/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/karl/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/karl/tmp/testhelper/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build398422980=/tmp/go-build -gno-record-gcc-switches"

What did you do?

go.mod:

module github.com/user/outer

go 1.12

inner/something_test.go:

package inner

import (
	"testing"

	"github.com/user/outer/test"
)

func TestIs1(t *testing.T) {
	test.AssertIs1(t, 1)
}

inner/something.go:

package inner

test/dummy.go:

package test

test/test_helpers_test.go:

package test

import "testing"

func AssertIs1(t *testing.T, value int) {
	if value != 1 {
		t.Errorf("Value %v is not 1", value)
	}
}

$ go test

What did you expect to see?

I expected the tests to run without error.

What did you see instead?

./something_test.go:10:2: undefined: test.AssertIs1
@mvdan
Copy link
Member

mvdan commented Jun 1, 2019

When you import a package, you only import its non-test code. This is true even if you're importing the package from a test file. I can't find an exact quote on this, though. The spec doesn't speak of this, because I think this is implemented in the Go tool via build tags.

@kstenerud
Copy link
Author

OK, but then how do I stop my test code from building when I call go build?

@mvdan
Copy link
Member

mvdan commented Jun 1, 2019

The files included in a package when built are the same files that are included in a package when you import it. So I'm not sure I see what you're trying to do.

It's normal to have a test helper/utility package, but often it's an internal package so that only the owner's packages can import it.

@kstenerud
Copy link
Author

kstenerud commented Jun 1, 2019

Normally, test code doesn't get compiled unless you call go test, at which point all *_test.go files get built as well.

What I want is to preserve this behavior and also be able to have common test code.

But the go tool seems to be one-or-the-other. If I put my common test code in a *_test.go file, it can't be imported by my other test code. If I put it in a regular *.go file, it gets compiled even when I'm not calling go test. For test code that takes a long time to build, this becomes a problem.

@davecheney
Copy link
Contributor

Yes, that is how it works. In your case outer appears to be a test helper package containing simple asset methods. Rename the files in that package so they do not end in _test.go and the code you supplied in your initial report will work as expected.

@kstenerud
Copy link
Author

That was just a toy project to illustrate the problem. My primary concern is with a bigger project with lots of test support code that I don't want compiling unless I'm actually running the tests.

@davecheney
Copy link
Contributor

I think this is mostly a hypothetical question. From the outline you provided outer will be cached by go build/test.

I know the go team care about compilation time. I suggest you try and iff there is a problem, raise a new bug with the concrete details.

@bcmills bcmills changed the title Test helper code not found cmd/go: Test helper code not found Jun 3, 2019
@bcmills
Copy link
Contributor

bcmills commented Jun 3, 2019

@kstenerud, I suspect that the error message you see is coming from the vet step rather than actually building the test. Can you verify what exit code go test actually returned?

(#29258 proposes to remove this extension mechanism, because it is confusing and can add overhead to builds even when it works.)

@bcmills bcmills added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 3, 2019
@bcmills bcmills added this to the Go1.13 milestone Jun 3, 2019
@bcmills
Copy link
Contributor

bcmills commented Jun 3, 2019

CC @jayconrod

@jayconrod
Copy link
Contributor

I looked into this a bit. It's working as intended. go test -vet=off reports the same error. go list -test -deps ./inner also makes it clear that the non-test variant of github.com/suer/outer/test is imported.

+1 to what @mvdan and @davecheney said above. It is possible to define test-only exported definitions, but they're only visible to tests in the same package. If you need test-only definitions visible to other packages, they need to be regular exported definitions in a regular package that's only imported by tests.

Just to recap on the current semantics:

  • Three variants may be built for each package.
    • The package under test (includes .go sources without "_test.go" suffix)
    • The internal test package (includes .go sources from the package under test, plus files with the "_test.go" suffix that don't have the _test package name suffix. (The tests in this example fall in this category))
    • The external test package (includes .go sources with the _test package name suffix only)
  • There's also a synthetic main package that imports the internal and external test packages.
  • In the import graph rooted at pmain, anything that imports the package under test is recompiled to import the internal test package instead.

The last point is the source of a lot of bugs and complication. The cached copies of packages recompiled due to that rule aren't usable for other tests, which blows up the build time. I think any expansion of those semantics would be too expensive and too confusing.

@golang golang locked and limited conversation to collaborators Jun 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

6 participants