go test can't find function in a same package - go

The directory structure is :
src
src/pkg
src/pkg/t1.go
src/pkg/t1_test.go
t1.go
package pkg
import (
"fmt"
)
func SayHI(){
fmt.Println("this is t1")
}
t1_test.go
package pkg
import (
"testing"
)
func TestXYZ(t *testing.T) {
SayHI()
}
Invoke go test from command line at dir src/pkg
go test t1_test.go
error:
./t1_test.go:8: undefined: SayHI
FAIL command-line-arguments [build failed]
but the function is there
thanks for any hints

It is working as intended.
jnml#fsc-r630:~/src/pkg$ go help test
usage: go test [-c] [-i] [build flags] [packages] [flags for test binary]
'Go test' automates testing the packages named by the import paths.
It prints a summary of the test results in the format:
ok archive/tar 0.011s
FAIL archive/zip 0.022s
ok compress/gzip 0.033s
...
followed by detailed output for each failed package.
'Go test' recompiles each package along with any files with names matching
the file pattern "*_test.go". These additional files can contain test functions,
benchmark functions, and example functions. See 'go help testfunc' for more.
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
The package is built in a temporary directory so it does not interfere with the
non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
-i
Install packages that are dependencies of the test.
Do not run the test.
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet.
jnml#fsc-r630:~/src/pkg$
In other words:
go test is okay.
go test pkg (assuming $GOPATH is ~ and the package is in ~/src/pkg) is okay.
go test whatever_test.go is not okay as that is not supported as documented above.
To select which tests to run use the -run <regular_expression> flag (where the <regular_expression> is interpreted as having wildcards on either end, like .*<regular_expression>.*). For example
$ go test -run Say # from within the package's directory
or
$ go test -run Say my/package/import/path # from anywhere

This is somewhat strange in Golang. To be honest it took me some time to figure a way out.
A simple work-around is to include them in the command, eg:
go test src/pkg/t1.go src/pkg/t1_test.go
IMHO, The best way is to keep it clean. So avoid having more than 1 file as dependency per test file. If you are using +1 file as dependency, consider creating a black-box test with a _test package and do not make use of any lowerCase internal vars.
This will avoid you having to deal with complicated dependencies on your day to day testing.

Run
go test ./...
This will find all the tests in all test files. To run individual tests, specify the dependencies like here.

I came across this Stackoverflow question after encountering the exact same issue myself: specifically, attempting to run go test and then seeing a build failure indicating that the function in question isn't defined. I see that this question is somewhat old now (asked 8 years ago) but in my case the issue was that I was attempting to write code in Go 1.16 that seems to now assume the presence/use of modules. See this page for a starting reference on modules and easy follow-along example.
All I had to do in my case was run go mod init [module name] and after that I could run go test without any issues.
Hopefully this is of some value to users coming to this page after using a more modern (1.16+) version of Go.

Related

How to test library functions in Golang

I'm learning Go so I'm writing some basic utils and libraries for fun that I can reuse in other modules.
When importing them inside another module (using go get for example), I can use them just fine.
As I understand, Go will look for a package main and a main function to know the entrypoint when trying to run a go app/module.
The thing is that the libraries are not in "package main", not in main.go and have no main function, so how am I supposed to use the cli and use go run . to test the behavior of my function?
Do I absolutely need to create another module with a main.go file inside a package main?
Or do I need to create a test file and use go test ?
Thank you!
Non-main packages (i.e., library packages) are not runnable.
To run the code in them, you must either run a main package that imports and runs their code, or write test functions in _test.go files to run the code. Note that test files are not just for unit tests; you can write whatever you want in them, and they can often be easier than creating a new main package for testing.
Modern IDEs now will allow you to easily run individual tests in debugging mode, so you can step through your code and see if it's working how you expect. If you prefer print debugging and doing everything from the command-line, you can still run an individual test and see the print output like this:
// something_test.go
package mylibrary
func TestSomeFunction(t *testing.T) {
SomeFunction()
}
go test mylibrary -v -run TestSomeFunction
go test is the preferred way to test Go code.
If you do not want to use go test for some reason, then use build constraints and the go run command to execute a main program from the same directory as your package.
Here's an example program with a build constraint. Place the file in the same directory as the package source files. The comment //go:build ignore is a build constraint that excludes the file from the package sources.
//go:build ignore
package main
import (
"your/package/import/path" // <-- modify to your path
"fmt"
)
func main() {
// do something with your package here.
fmt.Println("example")
}
Assuming that the above file is named program.go, run the program from the package directory with the command:
go run program.go
The go run command is OK for running toy or test programs like this. Prefer the go build command for anything else.

golang build constraints exclude all Go files in

I build a simple "Hello, World" wasm app like:
GOARCH=wasm GOOS=js go build -o lib.wasm main.go
All is well. But then I want to test my code in my local (Linux) environment. So I change it to a pretty standard:
package main
import "fmt"
func main () {
fmt.Println("test")
}
And do a simple:
go run .
but now I get:
package xxx: build constraints exclude all Go files in xxx
I understand that if I specify a wasm build, I can't expect to run it locally. But I'm not trying to do a wasm build anymore. There are no build constraints in my .go source file, and my go.mod file just has the package and go version.
If I copy these file to a new directory and only do the go run . without the wasm build - all is good.
And if I do:
go build filename.go
it works properly.
It's like something "remembers" that this directory was supposed to be built with wasm - but I cant find what/where.
Is there a cache or something elsewhere that's remembering some build settings that I need to clear? I've tried go clean and go clean -cache - no luck!
The answer seems to be that if a filename ends in wasm.go - go will assume this is indeed a wasm file.
This means that a normal build or run will fail (if you don't specify proper OS and arch) - though a run with an explicit filename (even if it ends in wasm.go will work correctly.
???

go test fails with "can't load package build constraints exclude all Go files"

When I run this command
go test -tags integration $(go list ./... | grep -v /vendor/)
go fails with this for some packages that has all tests marked with // +build !integration
can't load package: build constraints exclude all Go files
Is there a way I can make go test ignore those packages in this case, instead of failing? Thanks
You will only get that error if all the files in the package are excluded by your build constraints, not just the test files. If that's what you want, just add a single package file with no code and the package will still be able to be loaded. For example, many packages put their package level docs in a separate file, which you could use to always have a valid package:
// Package foo does foo
package foo
For whatever it's worth : I was seeing similar errors while building my code. In my case, my main file had // +build go1.13 at the top of it and I was trying to get the file built using go1.12.x. Removing +build go1.13 fixed the issue.
The package you are importing might contain some source files with a conditional complication flag, which is a directive you may find at the top of the files like:
//+build linux darwin windows
package main
import "fmt"
func main() {
fmt.Println("hello")
}
The +build directive followed by one or multiple platforms indicates where this source code is supposed to be compiled on.
Therefore, you can simply try removing this directive to resolve the failure.
It worked for me.
Following on from snowfox's answer, if you can't remove the directive (becuase it was likely put there for a reason), you can still run the test by using the tag that was applied to that file (more info here).
If your file start looks like this:
//go:build bar
package foo
Then you can run the test by running go test ./foo_test.go --tags=bar

Golang undefined variable

I have 2 go files:
/Users/username/go/src/Test/src/main/Test.go
package main
import "fmt"
func main() {
fmt.Printf(SomeVar)
}
and file /Users/username/go/src/Test/src/main/someFile.go
package main
const SomeVar = "someFile"
However I am constantly getting compiler error:
/Users/username/go/src/Test/src/main/Test.go:6: undefined: SomeVar
Can someone explain to me why is SomeVar labeled as undefined?
Try
go run Test.go someFile.go
Quote:
I think you're misunderstanding how the go tool works. You can do "go
build" in a directory, and it'll build the whole package (a package is
defined as all .go files in a directory). Same for go install, go
test, etc. Go run is the only one that requires you to specify
specific files... it's really only meant to be used on very small
programs, which generally only need a single file.
So do:
go build && ./program_name
See also
You code is correct:
someFile.go and Test.go belong to the same package (main)
SomeVar is a const declared at top level, so it has a package block scope, namely the main package block scope
as a consequence, SomeVar is visible and can be accessed in both files
(if you need to review scoping in Go, please refer to the Language Specification - Declarations and Scope).
Why do you get an undefined error then?
You probably launched go build Test.go or go run Test.go, both producing the following output, if launched from /Users/username/go/src/Test/src/main:
# command-line-arguments
./Test.go:6: undefined: SomeVar
You can find the reason here: Command go
If you launch go build or go run with a list of .go files, it treats them as a list of source files specifying a single package, i.e., it thinks there are no other pieces of code in the main package, hence the error.
The solution is including all the required .go files:
go build Test.go someFile.go
go run Test.go someFile.go
go build will also work with no arguments, building all the files it finds in the package as a result:
go build
Note 1: the above commands refer to the local package and, as such, must be launched from the /Users/username/go/src/Test/src/main directory
Note 2: though other answers already proposed valid solutions, I decided to add a few more details here to help the community, since this is a common question when you start working with Go :)
Due to landing on this page when I had a similar question, I'll include this answer alongside of what has already been stated. If you are using go run you may use:
go run . or go run .*
This question was also answered on this question
How to run all .go files within current directory through the command line (multi file package)

Build and reference my own local package in Go

I'm playing with Google Go and I'm having fun (!), but I'm having some problems with package subsystem.
I'm running Go 1.0.1 on Mac OS X Lion. I've build also various single file programs without problems (I've also build a small webapp using html/templates without problems and it compiles and runs without any error).
I've defined a "reusable" package (even.go):
package even
func Even(i int) bool {
return i % 2 == 0
}
func Odd(i int) bool {
return i % 2 == 1
}
and a consumer program (useeven.go):
package main
import (
"./even"
"fmt"
)
func main() {
a := 5
b := 6
fmt.Printf("%d is even %v?\n", a, even.Even(a))
fmt.Printf("%d is odd %v?\n", b, even.Odd(b))
}
But when I compile the "library" using
go build even.go
I got nothing... No errors, no message... What happens?
How should I do this?
The answer to your question, "How should I do this?" is explained in How to Write Go Code. It's really pretty important stuff and worth taking a look at.
The behavior of go build might seem puzzling, but is actually conventional for command line programs--no output means that the program ran successfully. So what did it do? For that your answer is in go help build
... Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
What, you wanted more? Of course. "How to Write Go Code" explains good ways of doing this. For a quick fix to your program, I'll explain that the go command expects each package and each executable program to be in a separate directory. If you just make a directory called even, immediately under the location of useeven.go, and move even.go to it, then go run useeven.go should run just as you have it.
go build only generates an output file when it builds a "single main package". If you want to output a file for your other package you should use go install. That will build and install that package to your pkgs directory.
As noted in a comment by the OP, go build and go run useeven.go work fine, once you put even.go in its own folder: ./even/even.go. There is a bit of Go magic in the ./ (in the import) that makes the "local package" build automatically without requiring it to be installed anywhere.
useeven/
├── even
│   └── even.go
└── useeven.go
If you wanted to make this work without the magic ./, then the library need to be installed. A quick-and-dirty way (at the risk of polluting your library namespace) of making this work for your project is to simply register the library's source location by using a symbolic link like so (in this example GOPATH is ~/go):
[ useeven ]
$ ln -s $(pwd)/even ~/go/src
Now when you build the program, it automatically performs a go get even to install an up-to-date version of your library.
Note that this doesn't make go install* work for the library, it just makes doing that unnecessary.
There are more idiomatic ways of doing this, if you're not in a hurry: How to import local packages in go?
The reason that output is not being generated here is because you're running the
go build even.go
command on the package and not the main go file. Doing so on the package will check for errors on the package, but because it's not a main with an output, no success messages will be generated. If there are issues with the package's contents, errors will be displayed, otherwise if it compiles fine there will be no output
Instead, you should run:
go build useeven.go
To create the binary, then to execute the binary and get output from the program:
./useeven

Resources