在 Go 中创建包的工作流程

Workflow for creating packages in Go

我了解到 Go 中的程序 运行 以 main 函数为起点。但我想知道为新包创建函数的工作流程是什么。

例如,在 python 中,当模块被直接调用时,我在模块中使用 __main__。当模块从另一个文件导入时 __main__ 将被忽略。这在您开发新模块时很有用。

if __name__ == "__main__":
    # Run module code here if module called directly

对于 Go,我使用 test.go 文件和 package main 以及我的 main.go 文件来测试我正在创建的包中的函数。

// test.go
package main

import (
    "newpackage"
)

func main() {
    newpackage.MyNewFunc()
}

是否有更好的方法来执行此操作,或者这是标准工作流程吗?谢谢。

您不使用 main 在 Go 中进行测试。 Go 有自己的测试框架。

首先,阅读 "How to Write Go Code",其中将解释 Go 的包布局和测试工具。最好使用它们,因为很多 Go 工具都需要这种布局。

创建包时,将其放在 ~/go/src 中的某处。我建议遵循使用您喜欢使用的存储库的惯例,即使对于您不一定要上传的内容也是如此。它有助于更​​好地组织; go get 也会将其他外部包放入 ~/go/src/

例如,即使我不打算将其上传到 Github,我也会使用 ~/go/src/github.com/schwern/newpackage/github.com/schwern 在 Go 源代码树中充当我的 "organization"。

将函数放入 package newpackage 下的 newpackage.go

$ cat ~/go/src/github.com/schwern/newpackage/newpackage.go 
package newpackage

func MyNewFunc() string {
    return "Hello!"
}

然后在 newpackage.go 旁边的 newpackage_test.go 进行测试。这些应该从Python就熟悉了,写了一堆Test*函数。与 Python 不同,它不使用断言。

$ cat ~/go/src/github.com/schwern/newpackage/newpackage_test.go 
package newpackage_test

import(
    "testing"
    "github.com/schwern/newpackage"
)

func TestMyNewFunc( t *testing.T ) {
    want := "Hello!"
    have := newpackage.MyNewFunc()

    if have != want {
        t.Errorf("MyNewFunc(): have: '%v', want: '%v'", have, want )
    }
}

如果你在包目录中 运行 go test 它将编译当前包及其依赖项,查找并编译包目录中的所有 *_test.go 文件,并执行它们的 Test* 函数。

$ pwd
/Users/schwern/go/src/github.com/schwern/newpackage
$ go test -v
=== RUN   TestMyNewFunc
--- PASS: TestMyNewFunc (0.00s)
PASS
ok      github.com/schwern/newpackage   0.013s

请注意,测试与它的测试位于不同的包中。这使它成为一个黑盒测试,它只能看到导出的(即大写)函数。您可以通过将测试放在同一个包中来进行玻璃盒测试,最好在单独的文件中进行,例如 newpackage_internal_test.go.

不幸的是 Go 没有断言函数,上面的 if 和对 t.Errorf 的调用是等价的。与其不断地手动滚动它们,不如有一些库提供像 stvp/assert 这样的断言函数。在 运行ning go get github.com/stvp/assert 之后你可以写...

package newpackage_test

import(
    "testing"
    "github.com/schwern/newpackage"
    "github.com/stvp/assert"
)

func TestMyNewFunc( t *testing.T ) {
    assert.Equal( t, newpackage.MyNewFunc(), "Hello!" )
}

如果您想要一个使用 newpackage 的可执行文件,它应该放在自己的包中。除非它是 newpackage.

的组成部分
$ cat ~/go/src/github.com/schwern/newexec/main.go 
package main

import (
    "fmt"
    "github.com/schwern/newpackage"
)

func main() {
    fmt.Println(newpackage.MyNewFunc())
}

如果你想测试mainthe testing package provides a special TestMain function...虽然我承认我并不完全理解它。与任何其他语言一样,最好将尽可能多的功能放入库调用中,并让 main 成为一个精简的包装器。