正确的软件包命名以使用Go语言进行测试


102

我在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"
)

请参阅字符串作为示例。

Go标准库似乎混合使用了策略1和策略2。我应该使用这三种策略中的哪一种?package *_test在我的测试包后面增加了一个痛苦,因为这意味着我无法测试我的包私有方法,但是也许有一个我不知道的隐藏优势?


9
这个问题只会引起不同的意见,但我会抛弃我。您不需要测试自己的私有方法。您想测试其他开发人员将使用的包的接口。如果测试失败,则说明您的私有方法需要查看。
布伦登

2
策略2 的[wire](github.com/btcsuite/btcd/blob/master/wire/msgtx_test.go)示例实际上现在也是策略1的示例...
durp

Answers:


130

您列出的三种策略之间的根本区别是测试代码是否与被测试代码位于同一程序包中。在使用的决定package myfuncpackage myfunc_test在测试文件取决于你是否要执行白盒黑箱测试。

在项目中同时使用两种方法都没有错。例如,您可以拥有myfunc_whitebox_test.gomyfunx_blackbox_test.go

测试代码包比较

  • 黑盒测试:使用package myfunc_test,这将确保您仅使用导出的标识符
  • 白盒测试:请使用,package myfunc以便您可以访问未导出的标识符。适用于需要访问未导出的变量,函数和方法的单元测试。

问题中列出的策略比较

  • 策略1:文件myfunc_test.go用途package myfunc-在这种情况下在测试的代码myfunc_test.go将在相同的封装中被测试的代码myfunc.go,这是myfunc在本例中。
  • 策略2:文件myfunc_test.go使用package myfunc_test—在这种情况下,myfunc_test.go“中的测试代码将被编译为单独的程序包,然后与主测试二进制文件链接并运行”。[来源:test.go源代码中的58-59行]
  • 策略3:文件myfunc_test.go使用package myfunc_testmyfunc使用点符号导入-这是策略2的变体,但使用点符号导入myfunc

1
应该注意的是,使用策略1还将使文件与_test.go被测试的软件包分开保存(与策略2相同的行为)。似乎没有按照github.com/golang/go/issues/15315
Kevin Deenanauth

我看到了强大的软件包使用策略3,但我不明白这有什么用?
PickBoy

1
我分叉了一个程序包并进行了更改,现在我的测试都在尝试导入原始存储库而不是分叉的程序包。使用策略3,我不必将“ github.com/original/link”更改为“ github.com/my/fork”,因为它只是引用“。”。代替。
nmarley

1
@KevinDeenanauth这让我感到惊讶。我以为我发现一个_test.go带有非_test软件包名称且包含一个的非软件包名称时就发现了一个陷阱,该名称func init()更改了一些用于测试的全局软件包变量。我错了。
Zyl

1
@nmarley .无法解决您的fork问题。这不是相对重要的。它只是将标识符“导入到当前包中”。
qaisjp

19

这取决于您的测试范围。高级别测试(集成,验收等)可能应该放在单独的程序包中,以确保您通过导出的API使用该程序包。

如果您有一个带有很多内部零件的大型包装,需要进行测试,则对您的测试使用相同的包装。但这并不是邀请您的测试访问任何私有状态。那将使重构成为一场噩梦。在go中编写结构时,我经常实现接口。是我从测试中调用的那些接口方法,而不是单独使用的所有辅助方法/函数。


13

您应尽可能使用策略1。您可以使用特殊的foo_test程序包名称来避免导入周期,但这主要是在此处,因此可以使用相同的机制来测试标准库。例如,strings由于testing软件包取决于,因此无法使用策略1进行测试strings。就像您说的那样,使用策略2或策略3,您无权访问软件包的私有标识符,因此通常最好不要使用它,除非您必须这样做。


10
在测试中不能访问私有标识符不是一种美德吗?
jub0bs

3
根据良好的测试实践,您不会测试代码工件的内部实现细节;做儿子,有代码味
Gerardo Lima

0

我想import .Golang CodeReviewComments添加一个重要说明:

import .由于循环依赖关系,该表格在测试中很有用,由于循环依赖,该表格不能成为要测试的软件包的一部分:

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

在这种情况下,测试文件不能放在foo包中,因为它使用 bar/testutil导入foo。因此,我们使用“导入”。允许文件伪装成foo包的一部分的格式,即使它不是。

除这种情况外,请勿import .在您的程序中使用。由于不清楚Quux之类的名称是否是当前包或导入包中的顶级标识符,因此使程序更难阅读。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.