我想测试一下我的主程序包中包含的一些函数,但我的测试似乎无法访问这些函数。
我的示例main.go文件如下所示:
package main
import (
"log"
)
func main() {
log.Printf(foo())
}
func foo() string {
return "Foo"
}
和我的main_test.go文件看起来像:
package main
import (
"testing"
)
func Foo(t testing.T) {
t.Error(foo())
}
当我运行go test main_test.go
我得到
# command-line-arguments
.\main_test.go:8: undefined: foo
FAIL command-line-arguments [build failed]
据我所知,即使我将测试文件移动到其他地方并尝试从main.go文件导入,我也无法导入它,因为它是package main
。
构建此类测试的正确方法是什么?我应该从main
包中删除所有内容,除了一个简单的主函数来运行所有内容然后在自己的包中测试函数,还是有办法让我在测试期间从主文件中调用这些函数?
在命令行上指定文件时,必须指定所有文件
这是我的运行:
$ ls
main.go main_test.go
$ go test *.go
ok command-line-arguments 0.003s
请注意,在我的版本中,我在命令行上同时运行了main.go和main_test.go
此外,您的_test文件不太正确,您需要将测试函数称为TestXXX并指向测试.T
这是修改后的版本:
package main
import (
"testing"
)
func TestFoo(t *testing.T) {
t.Error(foo())
}
和修改后的输出:
$ go test *.go
--- FAIL: TestFoo (0.00s)
main_test.go:8: Foo
FAIL
FAIL command-line-arguments 0.003s
单元测试只到目前为止。在某些时候,你必须实际运行该程序。然后你测试它是否与实际输入一起工作,从真实来源,产生实际输出到真实目的地。真的。
如果你想对单元进行单元测试,请将其移出main()。
这不是OP问题的直接答案,我总体上同意先前的答案和评论,敦促main
应该主要是打包函数的调用者。话虽这么说,这是我发现有用的测试可执行文件的方法。它使用log.Fataln
和exec.Command
。
main.go
,该函数调用log.Fatalln()以在返回之前向stderr写入消息。main_test.go
中,使用exec.Command(...)
和cmd.CombinedOutput()
运行您的程序,并选择参数来测试某些预期结果。例如:
func main() {
// Ensure we exit with an error code and log message
// when needed after deferred cleanups have run.
// Credit: https://medium.com/@matryer/golang-advent-calendar-day-three-fatally-exiting-a-command-line-tool-with-grace-874befeb64a4
var err error
defer func() {
if err != nil {
log.Fatalln(err)
}
}()
// Initialize and do stuff
// check for errors in the usual way
err = somefunc()
if err != nil {
err = fmt.Errorf("somefunc failed : %v", err)
return
}
// do more stuff ...
}
在main_test.go
中,对可能导致somefunc
失败的错误论据的测试看起来像:
func TestBadArgs(t *testing.T) {
var err error
cmd := exec.Command(yourprogname, "some", "bad", "args")
out, err := cmd.CombinedOutput()
sout := string(out) // because out is []byte
if err != nil && !strings.Contains(sout, "somefunc failed") {
fmt.Println(sout) // so we can see the full output
t.Errorf("%v", err)
}
}
请注意,来自err
的CombinedOutput()
是来自log.Fatalln对os.Exit(1)
的底层调用的非零退出代码。这就是为什么我们需要使用out
从somefunc
中提取错误消息。
exec
包也提供cmd.Run
和cmd.Output
。对于某些测试,这些可能比cmd.CombinedOutput
更合适。我还发现有一个TestMain(m *testing.M)
函数可以在运行测试之前和之后进行设置和清理。
func TestMain(m *testing.M) {
// call flag.Parse() here if TestMain uses flags
os.Mkdir("test", 0777) // set up a temporary dir for generate files
// Create whatever testfiles are needed in test/
// Run all tests and clean up
exitcode := m.Run()
os.RemoveAll("test") // remove the directory and its contents.
os.Exit(exitcode)
在两个来源中将包名称从main更改为foobar。在src / foobar下移动源文件。
mkdir -p src/foobar
mv main.go main_test.go src/foobar/
确保将GOPATH设置为src / foobar所在的文件夹。
export GOPATH=`pwd -P`
测试它
go test foobar