用于在go中创建包的工作流

Workflow for creating packages in Go

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

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

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

对于go,我使用一个带有package main的test.go文件,以及我的m a in.go文件来测试我正在创建的包中的函数。

1
2
3
4
5
6
7
8
9
10
// test.go
package main

import (
   "newpackage"
)

func main() {
    newpackage.MyNewFunc()
}

有没有更好的方法来实现这一点,或者这是标准的工作流程?谢谢。


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

首先,阅读"如何编写Go代码",这将解释Go的包布局和测试工具。最好是和它们一起使用,因为很多go工具都期望这种布局。

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

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

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

1
2
3
4
5
6
$ cat ~/go/src/github.com/schwern/newpackage/newpackage.go
package newpackage

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ 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*功能。

1
2
3
4
5
6
7
$ 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

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

不幸的是,go不附带断言函数,上面的if和对t.Errorf的调用是等效的。与其一直手工滚动它们,还有一些库提供诸如stvp/assert之类的断言函数。运行go get github.com/stvp/assert之后,你可以写…

1
2
3
4
5
6
7
8
9
10
11
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不可分割的一部分。

1
2
3
4
5
6
7
8
9
10
11
$ cat ~/go/src/github.com/schwern/newexec/main.go
package main

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

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

如果您想测试maintesting包提供了一个特殊的TestMain功能…虽然我承认我并不完全理解。像其他语言一样,最好将尽可能多的功能放入库调用中,并让main成为一个薄包装器。