Cra*_*nes 82 integration-testing unit-testing go testify
GoLang中是否存在分离单元测试和集成测试的最佳实践(作证)?我有混合的单元测试(不依赖于任何外部资源,因此运行速度非常快)和集成测试(它依赖于任何外部资源,因此运行速度较慢).因此,我希望能够控制是否包含集成测试go test.
最直接的技术似乎是在main中定义-integrate标志:
var runIntegrationTests = flag.Bool("integration", false
, "Run the integration tests (in addition to the unit tests)")
Run Code Online (Sandbox Code Playgroud)
然后在每个集成测试的顶部添加一个if语句:
if !*runIntegrationTests {
this.T().Skip("To run this test, use: go test -integration")
}
Run Code Online (Sandbox Code Playgroud)
这是我能做的最好的吗?我搜索了testify文档,看看是否有一个命名约定或者某些内容为我完成了这个,但没有找到任何东西.我错过了什么吗?
Ale*_*lex 131
@ Ainar-G提出了几个很好的模式来分开测试.
SoundCloud的这组Go实践建议使用构建标记(在构建包的"构建约束"部分中描述)来选择要运行的测试:
编写integration_test.go,并为其提供集成的构建标记.为服务地址和连接字符串定义(全局)标志,并在测试中使用它们.
Run Code Online (Sandbox Code Playgroud)// +build integration var fooAddr = flag.String(...) func TestToo(t *testing.T) { f, err := foo.Connect(*fooAddr) // ... }go test需要像build build一样构建标签,所以你可以调用
go test -tags=integration.它还合成了一个调用flag.Parse的包main,因此任何声明和可见的标志都将被处理并可用于您的测试.
作为类似选项,您还可以使用构建条件默认运行集成测试// +build !unit,然后通过运行按需禁用它们go test -tags=unit.
@adamc评论:
对于其他试图使用构建标记的人来说,重要的是// +build test注释是文件中的第一行,并且在注释后包含一个空行,否则-tags命令将忽略该指令.
此外,构建注释中使用的标记不能有破折号,但允许使用下划线.例如,// +build unit-tests将不会工作,而// +build unit_tests将.
Ain*_*r-G 45
我看到三种可能的解决方案 第一种是使用短模式进行单元测试.因此,您将使用go test -short单元测试和相同但没有-short标志来运行集成测试.标准库使用短模式来跳过长时间运行的测试,或者通过提供更简单的数据使它们运行得更快.
第二是使用公约,并打电话给你测试,无论是TestUnitFoo或TestIntegrationFoo再使用-run测试标志来表示要运行的测试.因此,您将go test -run 'Unit'用于单元测试和go test -run 'Integration'集成测试.
第三个选项是使用环境变量,并在测试设置中使用os.Getenv.然后,您将使用简单go test的单元测试和FOO_TEST_INTEGRATION=true go test集成测试.
我个人更喜欢这个-short解决方案,因为它更简单并且在标准库中使用,所以它似乎是分离/简化长时间运行测试的事实上的方法.但是-run和os.Getenv解决方案提供了更大的灵活性(因为涉及正则表达式,所以也需要更加谨慎-run).
edu*_*911 38
要在我的评论阐述为@ Ainar-G的出色答卷,在过去的一年我一直在使用的组合-short与Integration命名约定以达到两全其美.
建立标志先前迫使我有多个文件(services_test.go,services_integration_test.go,等).
相反,请在下面的示例中,前两个是单元测试,最后我有一个集成测试:
package services
import "testing"
func TestServiceFunc(t *testing.T) {
t.Parallel()
...
}
func TestInvalidServiceFunc3(t *testing.T) {
t.Parallel()
...
}
func TestPostgresVersionIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
...
}
Run Code Online (Sandbox Code Playgroud)
请注意,最后一个测试具有以下约定:
Integration的测试名称.-shortflag指令下运行.基本上,规范是:"正常编写所有测试.如果是长时间运行的测试,或者是集成测试,请遵循此命名约定并检查对-short同行的好处."
go test -v -short
Run Code Online (Sandbox Code Playgroud)
这为您提供了一组很好的消息,例如:
=== RUN TestPostgresVersionIntegration
--- SKIP: TestPostgresVersionIntegration (0.00s)
service_test.go:138: skipping integration test
Run Code Online (Sandbox Code Playgroud)
go test -run Integration
Run Code Online (Sandbox Code Playgroud)
这只运行集成测试.适用于生产中的烟雾测试金丝雀.
显然,这种方法的缺点是,如果有人运行go test,没有-short标志,它将默认运行所有测试 - 单元和集成测试.
实际上,如果您的项目足够大以进行单元和集成测试,那么您很可能正在使用可以Makefile在其中使用简单指令的位置go test -short.或者,只需将其放入您的README.md文件中并在当天调用即可.
我最近试图找到相同的解决方案。这些是我的标准:
前面提到的解决方案(自定义标志、自定义构建标记、环境变量)并没有真正满足上述所有条件,所以经过一番挖掘和尝试,我想出了这个解决方案:
package main
import (
"flag"
"regexp"
"testing"
)
func TestIntegration(t *testing.T) {
if m := flag.Lookup("test.run").Value.String(); m == "" || !regexp.MustCompile(m).MatchString(t.Name()) {
t.Skip("skipping as execution was not requested explicitly using go test -run")
}
t.Parallel()
t.Run("HelloWorld", testHelloWorld)
t.Run("SayHello", testSayHello)
}
Run Code Online (Sandbox Code Playgroud)
实现是简单和最小的。虽然它需要一个简单的测试约定,但它不太容易出错。进一步的改进可能是将代码导出到辅助函数。
仅对项目中的所有包运行集成测试:
go test -v ./... -run ^TestIntegration$
Run Code Online (Sandbox Code Playgroud)
运行所有测试(常规和集成):
go test -v ./... -run .\*
Run Code Online (Sandbox Code Playgroud)
仅运行常规测试:
go test -v ./...
Run Code Online (Sandbox Code Playgroud)
此解决方案无需工具即可正常运行,但 Makefile 或某些别名可以使其更易于用户使用。它还可以轻松集成到任何支持运行 go 测试的 IDE 中。
完整示例可以在这里找到:https : //github.com/sagikazarmark/modern-go-application
我鼓励您看看 Peter Bourgons 的方法,它很简单,并且避免了其他答案中建议的一些问题:https ://peter.bourgon.org/blog/2021/04/02/dont-use-build-tags -for-integration-tests.html