如何仅在测试时允许一个包访问另一个包的未导出数据?
How can I allow one package access to another package's unexported data only when testing?
在 Go 编程语言 的第 11.2.4 节中,有一个外部测试通过声明 IsSpace
访问 fmt.isSpace()
的示例在 fmt
的 export_test.go
文件中。这似乎是完美的解决方案,所以这就是我所做的:
a/a.go
:
package a
var x int
func Set(v int) {
x = v
}
a/a_test.go
:
package a
import "testing"
func TestSet(t *testing.T) {
Set(42)
if x != 42 {
t.Errorf("x == %d (expected 42)", x)
}
}
func Get() int {
return x
}
(运行 go test
在 a/
中工作正常。)
b/b.go
:
package b
import "path/to/a"
func CallSet() {
a.Set(105)
}
b/b_test.go
package b
import (
"testing"
"path/to/a"
)
func TestCallSet(t *testing.T) {
CallSet()
if r := a.Get(); r != 105 {
t.Errorf("Get() == %d (expected 105)", r)
}
}
不幸的是,当我在 b/
中 运行 go test
时,我得到:
./b_test.go:11: undefined: a.Get
尝试 运行 同时进行两组测试 go test ./...
没有帮助。
经过相当多的探索后,我发现“The *_test.go files are compiled into the package only when running go test for that package”(强调我的)。 (因此,换句话说,我可以从 a/
中的 a_test
外部测试包访问 a.Get
,但不能从 a/
之外的任何包访问 a.Get
。)
有没有其他方法可以让一个包的测试访问另一个包的其他内部数据,以进行集成测试?
Is there some other way I can allow tests from one package to access otherwise-internal data from another package, for integration testing purposes?
没有。没有。
如前所述,无法"grant"访问未导出的标识符。
虽然需要/证明对 fmt
包测试的一些说明。
有两种测试:黑盒测试和白盒测试。
黑盒 测试是将包视为 "black-box",并且仅通过其导出的标识符(通过其 "public API" ,其他包看到的)。在这种情况下,测试文件具有不同的包名称(例如,测试 fmt
包时 fmt_test
)。
白盒 测试是指同时使用包的导出和未导出标识符。要创建白盒测试,您在测试文件中指定与被测试包相同的包名称(因此,fmt
在 fmt
包测试的情况下)。
标准库的 fmt
包中包含的测试 打算 成为黑盒测试,但那样就无法测试所有内容。所以 Go 的作者选择了 mixed 版本:他们包含了一个 export_test.go
测试文件,它使用相同的包声明(package fmt
)所以它可以访问未导出的fmt
包的标识符,以及 "exports" 2 个标识符,以便其他(黑盒)测试文件可以访问:
var IsSpace = isSpace
var Parsenum = parsenum
作者这样做是因为他们想尽量减少使用未导出的标识符,所以这明确标记了使用哪些未导出的标识符,并且基本上充当 "bridge" 之间的 [=] 11=] 包和 fmt
包的黑盒测试。
这里要注意的一件事是,这些只会 "exported" 到 fmt
包的(黑盒)测试(和 fmt
的白盒测试当然),而不是其他包或其他包的测试。原因很简单,因为构建包时不会解析和编译测试文件,只有当包测试是 运行.
解决方案?
未导出的标识符是针对包本身的,与其他人无关。这意味着没有其他包应该想要测试它们。如果需要对其进行测试,则必须在包自己的测试中完成。
如果对于集成测试您需要访问未导出的标识符,则包必须导出 "something" 以公开值(或其中的某些部分),或者在不导出敏感数据或实现的情况下帮助测试细节。如果包 API 设计良好且测试彻底,则永远(很少)需要它。
在 Go 编程语言 的第 11.2.4 节中,有一个外部测试通过声明 IsSpace
访问 fmt.isSpace()
的示例在 fmt
的 export_test.go
文件中。这似乎是完美的解决方案,所以这就是我所做的:
a/a.go
:
package a
var x int
func Set(v int) {
x = v
}
a/a_test.go
:
package a
import "testing"
func TestSet(t *testing.T) {
Set(42)
if x != 42 {
t.Errorf("x == %d (expected 42)", x)
}
}
func Get() int {
return x
}
(运行 go test
在 a/
中工作正常。)
b/b.go
:
package b
import "path/to/a"
func CallSet() {
a.Set(105)
}
b/b_test.go
package b
import (
"testing"
"path/to/a"
)
func TestCallSet(t *testing.T) {
CallSet()
if r := a.Get(); r != 105 {
t.Errorf("Get() == %d (expected 105)", r)
}
}
不幸的是,当我在 b/
中 运行 go test
时,我得到:
./b_test.go:11: undefined: a.Get
尝试 运行 同时进行两组测试 go test ./...
没有帮助。
经过相当多的探索后,我发现“The *_test.go files are compiled into the package only when running go test for that package”(强调我的)。 (因此,换句话说,我可以从 a/
中的 a_test
外部测试包访问 a.Get
,但不能从 a/
之外的任何包访问 a.Get
。)
有没有其他方法可以让一个包的测试访问另一个包的其他内部数据,以进行集成测试?
Is there some other way I can allow tests from one package to access otherwise-internal data from another package, for integration testing purposes?
没有。没有。
如前所述,无法"grant"访问未导出的标识符。
虽然需要/证明对 fmt
包测试的一些说明。
有两种测试:黑盒测试和白盒测试。
黑盒 测试是将包视为 "black-box",并且仅通过其导出的标识符(通过其 "public API" ,其他包看到的)。在这种情况下,测试文件具有不同的包名称(例如,测试 fmt
包时 fmt_test
)。
白盒 测试是指同时使用包的导出和未导出标识符。要创建白盒测试,您在测试文件中指定与被测试包相同的包名称(因此,fmt
在 fmt
包测试的情况下)。
标准库的 fmt
包中包含的测试 打算 成为黑盒测试,但那样就无法测试所有内容。所以 Go 的作者选择了 mixed 版本:他们包含了一个 export_test.go
测试文件,它使用相同的包声明(package fmt
)所以它可以访问未导出的fmt
包的标识符,以及 "exports" 2 个标识符,以便其他(黑盒)测试文件可以访问:
var IsSpace = isSpace
var Parsenum = parsenum
作者这样做是因为他们想尽量减少使用未导出的标识符,所以这明确标记了使用哪些未导出的标识符,并且基本上充当 "bridge" 之间的 [=] 11=] 包和 fmt
包的黑盒测试。
这里要注意的一件事是,这些只会 "exported" 到 fmt
包的(黑盒)测试(和 fmt
的白盒测试当然),而不是其他包或其他包的测试。原因很简单,因为构建包时不会解析和编译测试文件,只有当包测试是 运行.
解决方案?
未导出的标识符是针对包本身的,与其他人无关。这意味着没有其他包应该想要测试它们。如果需要对其进行测试,则必须在包自己的测试中完成。
如果对于集成测试您需要访问未导出的标识符,则包必须导出 "something" 以公开值(或其中的某些部分),或者在不导出敏感数据或实现的情况下帮助测试细节。如果包 API 设计良好且测试彻底,则永远(很少)需要它。