当我编写接口时,通常可以方便地在与接口相同的包中定义我的测试,然后定义多个实现接口集的包,例如。
package/
package/impl/x <-- Implementation X
package/impl/y <-- Implementation Y
是否有一种简单的方法可以在子包中运行相同的测试套件(在本例中,位于package / * _ test.go中)?
到目前为止,我提出的最佳解决方案是添加一个测试包:
package/tests/
实现测试套件,并在每个实现中进行测试以运行测试,但这有两个缺点:
1)包/测试中的测试不在_test.go文件中,最终成为实际库的一部分,由godoc等记录。
2)包/测试中的测试由自定义测试运行器运行,该测试运行器必须基本上复制&#39; go test&#39;的所有功能。扫描go测试并运行它们。
似乎是一个非常俗气的解决方案。
有更好的方法吗?
答案 0 :(得分:7)
我真的不喜欢使用单独的测试库。如果您有一个接口,并且每个接口都有通用测试,那么实现该接口的其他人也可能希望使用这些测试。
您可以创建包含函数
的包"package/test"
// functions needed for each implementation to test it
type Tester struct {
func New() package.Interface
func (*package.Interface) Done()
// whatever you need. Leave nil if function does not apply
}
func TestInterface(t *testing.T, tester Tester)
请注意TestInterface
的签名与go test
期望的签名不匹配。现在,对于每个包package/impl/x
,您添加一个文件generic_test.go
:
package x
import "testing"
import "package/test"
// run generic tests on this particular implementation
func TestInterface(t *testing.T) {
test.TestInterface(t,test.Tester{New:New})
}
其中New()
是您的实现的构造函数。该方案的优点是
go test
兼容(大加!)当然,在某些情况下,您需要一个更复杂的TestInterface
函数,但这是基本的想法。
答案 1 :(得分:1)
如果您共享一段代码以供不同包重用,那么是的,根据定义它是一个库。即使仅用于从* _test.go文件进行测试。它与在_test.go文件中导入“fmt”的“测试”没什么不同。并且由godoc记录的API是一个加号,而不是减去恕我直言。
答案 2 :(得分:1)
也许有些事情在这里混淆了一下: 如果package a只定义了一个接口,那么就没有代码 测试作为Go中的接口是免费实现的。
所以我假设你的接口中的方法在包a中 有约束。例如。在
interface Walker {
Walk(step int)
Tired() bool
}
你的合同假设Tired如果超过则返回true 已经走了500步(否则为假) 并且您的测试代码会检查这些依赖项 (或假设,合同,不变量,不管你 把它命名。)
如果是这种情况,我会提供(在包a中)导出 功能
func TestWalkerContract(w Walker) error {
w.Walk(100)
if w.Tired() { return errors.New("Tired after 100 steps") }
w.Walk(450)
if !w.Tired() { return errors.New("Not tired after 100+450 steps") }
}
哪些文件合同正确并且可以由包使用 b和c,其中类型实现了walker来测试它们的实现 在b_test.go和c_test.go中。恕我直言,这些都是完全可以的 像godW一样显示TestWalkerContract之类的函数。
P.S。比Walk和Tired更常见的可能是错误状态 保存并报告,直到清除/重置。