提问者:小点点

在Go中分离单元测试和集成测试


在GoLong(作证)中,是否有分离单元测试和集成测试的既定最佳实践?我混合了单元测试(不依赖任何外部资源,因此运行速度非常快)和集成测试(依赖任何外部资源,因此运行速度较慢)。因此,我希望能够控制当我说go test时是否包含集成测试。

最直接的技术似乎是在main中定义一个-积分标志:

var runIntegrationTests = flag.Bool("integration", false
    , "Run the integration tests (in addition to the unit tests)")

然后在每个联调的顶部添加一个if语句:

if !*runIntegrationTests {
    this.T().Skip("To run this test, use: go test -integration")
}

这是我能做的最好的吗?我搜索了证词留档,看看是否有命名约定或其他东西可以为我实现这一点,但没有找到任何东西。我错过了什么吗?


共3个答案

匿名用户

@Ainar-G提出了几个很好的模式来分开测试。

SoundCloud的这套Go实践建议使用构建标签(在构建包的“构建约束”部分中描述)来选择要运行的测试:

编写一个integration_test. go,并给它一个集成的构建标签。为服务地址和连接字符串等内容定义(全局)标志,并在测试中使用它们。

// +build integration

var fooAddr = flag.String(...)

func TestToo(t *testing.T) {
    f, err := foo.Connect(*fooAddr)
    // ...
}

go test就像go build一样采用构建标签,因此您可以调用go test-tags=集成。它还合成了一个调用标记的包main。Parse,因此任何声明和可见的标志都将被处理并可用于您的测试。

作为类似的选项,您也可以使用构建条件//build! unit默认运行集成测试,然后通过运行go test-tags=unit按需禁用它们。

@adamc评论:

对于任何其他尝试使用构建标记的人来说,//build test注释是文件中的第一行,并且在注释之后包含一个空行是很重要的,否则-tags命令将忽略该指令。

此外,构建注释中使用的标记不能有破折号,尽管允许使用下划线。例如,//build unit-test将不起作用,而//buildunit_tests将起作用。

匿名用户

为了详细说明我对@Ainar-G出色回答的评论,在过去的一年里,我一直在使用-短集成命名约定的组合来实现两全其美。

构建标志以前强迫我有多个文件(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")
    }
    ...
}

请注意,最后一个测试具有以下约定:

  1. 在测试名称中使用集成
  2. 检查是否在-短标志指令下运行。

基本上,规范是这样的:“正常编写所有测试。如果它是一个长时间运行的测试,或者一个联调,遵循这个命名约定并检查-短以善待你的同行。”

go test -v -short

这为您提供了一组不错的消息,例如:

=== RUN   TestPostgresVersionIntegration
--- SKIP: TestPostgresVersionIntegration (0.00s)
        service_test.go:138: skipping integration test
go test -run Integration

这只运行集成测试。对于生产中的冒烟测试金丝雀很有用。

显然,这种方法的缺点是,如果任何人运行go test,如果没有-短标志,它将默认运行所有测试-单元和集成测试。

实际上,如果您的项目足够大,可以进行单元测试和集成测试,那么您很可能正在使用Makefile,其中可以使用简单的指令来使用go test-短。或者,只需将其放在您的README.md文件中,然后收工。

匿名用户

我看到了三种可能的解决方案。第一种是使用单元测试的短模式。因此,您可以在单元测试中使用go test-短,同样的,但没有-短标志来运行您的集成测试。标准库使用短模式来跳过长时间运行的测试,或者通过提供更简单的数据使它们运行得更快。

第二种是使用约定并调用您的测试TestUnitFooTestIntegrationFoo,然后使用-run测试标志来表示要运行的测试。因此,您将使用go test-run'Unit'进行单元测试,使用go test-run'Integr'进行集成测试。

第三种选择是使用环境变量,并在您的测试设置中使用os. Getenv获取它。然后,您将使用简单的go test进行单元测试,并使用FOO_TEST_INTEGRATION=true go test进行集成测试。

我个人更喜欢-短解决方案,因为它更简单,并且在标准库中使用,所以它似乎是分离/简化长时间运行的测试的事实上的方式。但是-runos. Getenv解决方案提供了更大的灵活性(也需要更加小心,因为regexp与-run有关)。