前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言中常见100问题-#82 Not categorizing tests

Go语言中常见100问题-#82 Not categorizing tests

作者头像
数据小冰
发布2022-08-15 15:30:17
3830
发布2022-08-15 15:30:17
举报
文章被收录于专栏:数据小冰
不知道分类进行测试

软件测试中有一个金字塔模型,该模型将测试分为不同类别。如下图所示,单元测试位于金字塔最下面一层。通常,沿着金字塔越往上走,测试就越复杂,运行速度越慢,并且越难以保证它们的确定性,因此在实际开发中,团队应该有更多的单元测试。此外,单元测试还有编写成本低、执行速度快和确定性高等优点。

在进行测试前,首先要明确的是运行哪种测试。根据项目所处在生命周期中的阶段,我们可能希望仅运行单元测试或运行项目中的所有测试。如果不对测试的内容进行分类可能会费时费力,并且会失去测试范围的准确性。本文将深入讨论Go语言中对测试进行分类的三种主要方法。

通过标签(tags)进行分类

对测试进行分类的最常用方法是使用编译标签(build tags). build tags是Go源文件开头的特殊注释,后面跟一个空行,像下面这样。

代码语言:javascript
复制
//go:build foo

package bar

上面的bar.go文件包含foo标签。注意,在一个包中,可以有多个文件它们有不同的标签.

「NOTE: 在Go1.17中,原来的语法 // +build foo 被//go:build foo取代。在Go1.18版中,可以通过gofmt将旧语法格式迁移到新格式。」

build tags主要有两种使用场景。第一个场景是作为构建/编译应用程序的条件选项,例如,如果我们希望仅在启用cgo时才包含源文件(cgo是一种让Go调用c代码的方法),可以在源文件中添加 //go:build cgo 标签。第二个场景是如果我们要将测试内容归类为集成测试,可以添加特定的编译标记,例如像下面这样在文件中添加integration标签。

代码语言:javascript
复制
//go:build integration

package db

import (
        "testing"
)

func TestInsert(t *testing.T) {
        // ...
}

上面的文件通过添加集成标签来区分该文件包含集成测试。使用编译标签(build tags)的好处是可以选择执行哪种测试。例如,假设有一个包中包含两个测试文件:

  • db_test.go文件,包含integration标签
  • contract_test.go,不含任何编译标签

如果我们在这个包中执行go test命令(不带标签选项),将只会运行没有tags的测试文件,即这里只会运行contract_test.go。

代码语言:javascript
复制
go test -v .
=== RUN   TestContract
--- PASS: TestContract (0.00s)
PASS

如果在执行go test时提供integration标签,这时运行将会包含db_test.go, 即contract_test.go和db_test.go文件都会运行。

代码语言:javascript
复制
 go test --tags=integration -v .                                                                                   
=== RUN   TestContract
--- PASS: TestContract (0.00s)
=== RUN   TestInsert
--- PASS: TestInsert (0.00s)
PASS

通过上面的测试验证可以看到,如果在执行go test提供标签,将会运行含有匹配标签和不带标签的测试文件。那现在,如果我们只想运行含有integration标签的文件怎么办?一种可行的方法是在测试文件中添加否定标签,例如,这里在contract_test.go文件中添加!integration标签。使用!integration标签意味着在执行go test时未添加--tags=integration时才会包含此测试文件。

代码语言:javascript
复制
//go:build !integration

package db

import (
        "testing"
)

func TestContract(t *testing.T) {
        // ...
}

此时,在执行go test时:

  • 如果提供integration标签选项,将只会运行db_test.go
  • 如果不提供integration标签选项,将只会运行contract_test.go

提供integration标签时运行结果如下:

代码语言:javascript
复制
go test --tags=integration -v .                                                                                 
=== RUN   TestInsert
--- PASS: TestInsert (0.00s)
PASS

不提供标签时运行结果如下:

代码语言:javascript
复制
go test -v .  
=== RUN   TestContract
--- PASS: TestContract (0.00s)
PASS

通过环境变量进行分类

前一小节讲述了可以通过tags区分测试文件,选择特定的测试文件运行。本小节讲述通过环境变量的方法可以在测试函数级别进行分类测试。正如Go社区成员Peter Bourgon所说,通过build tags方法进行分类测试有一个大的缺点:在测试时缺少输出已忽略运行某些测试文件信息。在上小节的例子中,当我们执行go test不带标签选项时,只输出了已执行的测试函数(contract_test.go文件中的测试函数)信息,像db_test.go没有运行,但没有给任何提示。

代码语言:javascript
复制
go test -v .
=== RUN   TestUnit
--- PASS: TestUnit (0.01s)
PASS
ok      db  0.319s

如果我们对标签的处理方式不够小心,可能会忘记现有的测试。出于这个原因,一些项目倾向使用环境变量来进行分类测试。例如,我们可以通过检查特定环境变量并跳过对应的测试来实现TestInsert集成测试。

代码语言:javascript
复制
func TestInsert(t *testing.T) {
        if os.Getenv("INTEGRATION") != "true" {
                t.Skip("skipping integration test")
        }

        // ...
}

如果环境变量INTEGRATION没有设置为true,则会跳过测试并输出一条日志。

代码语言:javascript
复制
go test -v .
=== RUN   TestInsert
    db_integration_test.go:12: skipping integration test
--- SKIP: TestInsert (0.00s)
=== RUN   TestUnit
--- PASS: TestUnit (0.00s)
PASS
ok      db  0.319s

使用环境变量方法的一个优点是明确跳过的测试及其原因,虽然这种方法可能不如build tags使用的广泛,但还是值得了解,因为它具有标签分类没有的一个优点。

通过短模式进行分类

还可以根据执行的速度对测试进行分类,实际中, 我们可能不得不将短期与长期运行的测试区分开。举一个例子,现在我们有一组单元测试,但有一个执行的速度很慢。因此,我们希望以特定的方式对其进行分类,这样我们就不必每次都运行它(例如在保存文件之后进行的操作逻辑)。短模式(short mode)提供了这种分类方法。

代码语言:javascript
复制
func TestLongRunning(t *testing.T) {
        if testing.Short() {
                t.Skip("skipping long-running test")
        }
        // ...
}

使用testing.Short,可以判断在运行测试时是否启用了短模式。然后使用t.Skip跳过测试。如果要使用短模式运行测试,在执行go test命令时携带 -short参数。

代码语言:javascript
复制
go test -short -v .
=== RUN   TestLongRunning
    foo_test.go:9: skipping long-running test
--- SKIP: TestLongRunning (0.00s)
PASS
ok      foo  0.174s

通过上面的测试输出日志可以看到,TestLongRunning被排除并从执行的测试中显示跳过。注意,短模式适用于单个测试项(像这里的TestLongRunning),它不是针对文件级别的。

总结,对测试进行分类是进行成功测试的最佳实践。本文讲述了三种对测试进行分类的方法:

  • build tags: 在文件级别对测试进行分类,通过设置标签,可以选择运行哪些测试文件
  • environment variable:使用环境变量来标记特定的测试
  • short mode:从执行速度快慢维度对测试进行分类,使用短模式区分出慢测试项

在测试时,不局限于上面的一种方法,我们也可以结合多种方法。例如,如果我们的程序包含长时间运行的单元测试,则可以使用编译标签结合短模式,或者采用环境变量和短模式对其进行分类测试。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据小冰 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 不知道分类进行测试
    • 通过标签(tags)进行分类
      • 通过环境变量进行分类
        • 通过短模式进行分类
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档