我在Go中看到了几种不同的测试包命名策略,并想知道每种方法的优缺点以及应该使用哪种方法。
策略1:
文件名:github.com/user/myfunc.go
package myfunc
测试文件名:github.com/user/myfunc_test.go
package myfunc
有关示例,请参阅bzip2。
策略2:
文件名:github.com/user/myfunc.go
package myfunc
测试文件名:github.com/user/myfunc_test.go
package myfunc_test
import (
"github.com/user/myfunc"
)
有关示例,请参阅wire。
策略3:
文件名:github.com/user/myfunc.go
package myfunc
测试文件名:github.com/user/myfunc_test.go
package myfunc_test
import (
. "myfunc"
)
有关示例,请参阅strings。
Go标准库似乎使用策略1和2的混合物。我应该使用哪三个?将package *_test
添加到我的测试包中会很痛苦,因为这意味着我无法测试我的包私有方法,但可能有一个我不知道的隐藏优势?
答案 0 :(得分:84)
您列出的三种策略之间的根本区别在于测试代码是否与被测代码位于同一个包中。在测试文件中使用package myfunc
或package myfunc_test
的决定取决于您是要执行white-box还是black-box测试。
在项目中使用这两种方法没有任何问题。例如,您可以拥有myfunc_whitebox_test.go
和myfunx_blackbox_test.go
。
package myfunc_test
,这将确保您只使用exported identifiers。package myfunc
,以便您可以访问未导出的标识符。适用于需要访问非导出变量,函数和方法的单元测试。myfunc_test.go
使用package myfunc
- 在这种情况下,myfunc_test.go
中的测试代码与正在测试的代码位于同一个包中在myfunc.go
中,在此示例中为myfunc
。myfunc_test.go
使用package myfunc_test
- 在这种情况下,myfunc_test.go
中的测试代码将被编译为单独的包,然后链接并运行主测试二进制文件。“ [来源:test.go源代码中的第58-59行] myfunc_test.go
使用package myfunc_test
但使用点表示法导入myfunc
- 这是策略2的变体,但使用点导入符号myfunc
。答案 1 :(得分:17)
您应该尽可能使用策略1。您可以使用特殊的foo_test
包名称来避免导入周期,但这主要是因为标准库可以使用相同的机制进行测试。例如,strings
无法使用策略1进行测试,因为testing
包取决于strings
。正如您所说,使用策略2或3,您无权访问程序包的私有标识符,因此除非必须,否则通常最好不要使用它。
答案 2 :(得分:17)
这取决于您的测试范围。高级测试(集成,验收等)应该放在一个单独的包中,以确保您通过导出的API使用该包。
如果你有一个包含大量内部组件的大型软件包需要进行测试,那么请使用相同的软件包进行测试。但这不是邀请您的测试访问任何私有状态。这将使重构成为一场噩梦。 When I write structs in go我经常实现接口。我从测试中调用的是那些接口方法,而不是单独的所有辅助方法/函数。
答案 3 :(得分:0)
我想在Golang CodeReviewComments中添加有关import .
的一个重要说明:
import .
形式可用于由于 circular 依赖性而导致的测试,
不能成为要测试的包装的一部分:
package foo_test
import (
"bar/testutil" // also imports "foo"
. "foo"
)
在这种情况下,测试文件不能放在foo包中,因为它使用
bar/testutil
,它导入foo。因此,我们使用“导入”。表格让文件
假装不是foo软件包的一部分。
除这种情况外,请勿在程序中使用import .
。
这使得程序更难阅读,因为尚不清楚名称是否
例如Quux是当前包或导入包中的顶级标识符。