零代码上手测试:Go语言内置测试框架介绍

简介: 零代码上手测试:Go语言内置测试框架介绍

/ Go 语言 Test 测试函数详解 /

 

一、概述

测试是保证代码质量非常重要的一环。Go 语言内置了测试功能,可以轻松编写单元测试。本文将详细介绍 Go 语言 testing 测试功能中的 Test 测试函数,包括使用方式、测试组织、benchmark 性能测试、示例代码等。

主要内容:

  • Test 函数基本用法
  • 子测试与 Setup/Teardown
  • 测试组织结构
  • 测试 cover 率
  • 基准测试 benchmark
  • 测试主函数
  • 测试框架集成
  • 并发测试
  • 示例 Demo

通过本文可以全面了解 Go 语言 Test 测试函数,并能应用到实际项目中去提高代码质量。


 

二、Test 函数基本用法

Go 语言中单元测试文件以 _test.go 命名,测试方法名以 Test 开头:

func TestAdd(t *testing.T) {
  total := Add(1, 2)
  if total != 3 {
    t.Errorf("Add(1, 2) failed, got %d", total) 
  }
}

测试函数 TestAdd 中,使用 t.Errorf 来报告错误信息。

testing.T 实际上是一个接口,代表一个测试对象,不同的测试框架都可以实现这个接口。我们通过它来记录测试日志。

常用的方法有:

  • t.Error/t.Errorf: 记录错误
  • t.Fatal/t.Fatalf: 记录错误并退出
  • t.Log/t.Logf: 记录日志
  • t.Parallel: 并发测试

Go 语言内置的 testing 框架实现了 testing.T 接口。


 

三、子测试与 Setup/Teardown

我们可以通过 Run 方法执行子测试,还可以通过 Setup/Teardown 执行初始化和清理:

func TestMulti(t *testing.T) {
  // 初始化代码
  t.Setup(func() {
    // ..
  })
  t.Run("A=1", func(t *testing.T) {
    t.Log("A=1")
  })
  t.Run("A=2", func(t *testing.T) {
    t.Log("A=2") 
  })
  // 清理代码
  t.Teardown(func() {
    // ..
  })
}

这样可以非常方便地对测试进行分组。


 

四、测试组织结构

复杂的测试我们可以通过以下结构组织:

  • testMain:全局测试初始化和 ErrorHandler
  • TestSuite:测试套件初始化,全局资源
  • TestCase:一个测试用例,一组相关的测试
  • Test:单个测试函数
  • subTest:子测试用例

这种层次清晰的测试组织结构,可以让我们完整体系地编写测试代码。


 

五、测试覆盖率

测试覆盖率(cover rage)可以度量测试的覆盖面。

启用 coverrage 实际上是通过注入计数器来实现。以示例:

func TestA(t *testing.T) {
  // 开启coverrage
  c := cover.NewCounter("testfile")
  c.Enable()
  // 测试代码
  ...
  // 查看测试覆盖率
  cover.Percent(c)
}

执行后可以得到运行的测试覆盖了百分之多少的代码。

这可以帮助我们分析还需要增加哪些测试。


 

六、基准测试

基准测试 Benchmark 可以测试函数/代码片段的性能。基准测试以 Benchmark 为前缀:

func BenchmarkAdd(b *testing.B) {
  for i := 0; i < b.N; i++ {
    Add(1, 2)
  }
}

运行基准测试,可以得到代码执行的时间。这样可以比较不同实现的性能。

我们应该针对关键路径进行基准测试,找到并优化速度慢的代码。


 

七、测试主函数

每份测试代码需要一个 TestMain 函数作为入口:

func TestMain(m *testing.M) {
  // 初始化代码
  // 执行测试
  code := m.Run() 
  // 释放资源
  ...
  os.Exit(code)
}

TestMain 会先执行初始化操作,然后使用 m.Run 执行测试代码,最后释放资源并退出程序。/


 

八、测试框架集成

Go 语言内置 testing 框架非常简单。我们也可以集成其他测试框架。

常见的集成方式是实现 testing.TB 接口。以集成 Ginkgo 为例:

type TestWrapper struct {
  *testing.T
}
func (t *TestWrapper) Fail() {
  t.FailNow()
}
var RunSpecs = func(t *testing.T) {
  RegisterFailHandler(Fail)
  var tr TestReporter
  RunSpecsWithDefaultAndCustomReporters(t, "SuiteName", []Reporter{tr})
}
func TestSuite(t *testing.T) {
  RunSpecs(t)
}

这样我们就可以在 Go 测试中无缝使用 Ginkgo 的 BDD 语法了。


 

九、并发测试

Go 语言支持并发执行测试来提高效率:

func TestParallel(t *testing.T) {
  for _, fn := range tests {
    t.Run(fn.Name(), func(t *testing.T) {
      t.Parallel() // 并发执行测试函数
      fn(t)
    })
  }
}

通过 t.Parallel()可以启用并发测试。

需要注意并发访问全局资源的锁保护以避免冲突。


 

十、完整示例

我们来看一个完整的测试示例:

// 测试对象
type Foo struct {} 
// 测试函数
func TestFoo(t *testing.T) {
  // 测试套件初始化
  t.SetupTestSuite(func() {
    // ..
  })
  t.Run("A=1", func(t *testing.T) {
    t.Parallel() // 并发
    // 测试前初始化 
    t.Setup(func() {
      // ..
    })
    // 调用测试对象  
    f := Foo{}
    // 测试逻辑  
    ...
    // 测试后清理
    t.Teardown(func() {
      // .. 
    })
  })
  // 基准测试
  t.Benchmark("BM", func(b *testing.B) {
    for i := 0; i < b.N; i++ {
      // ..
    }
  })
  // 测试套件结束处理
  t.TeardownTestSuite(func() {
    // ..
  })  
}
func TestMain(m *testing.M) {
  // 初始化
  os.Exit(m.Run())
}

这样一个完整的测试组织结构,可以让我们的测试代码看起来非常清晰系统。


 

十一、总结

通过本文的介绍,我们已经可以熟练使用 Go 语言中的测试功能,编写规范的单元测试了。

testing 提供了强大灵活的测试支持,可以编写出高质量可靠的测试代码。这对于提高我们项目的健壮性非常重要。

在后续的 Go 项目中,希望大家积极编写 Unit Test,让代码质量达到更高的层次。


目录
相关文章
|
2天前
|
人工智能 Go 调度
掌握Go并发:Go语言并发编程深度解析
掌握Go并发:Go语言并发编程深度解析
|
8天前
|
SQL 安全 数据库连接
《Go 简易速速上手小册》第6章:错误处理和测试(2024 最新版)(上)
《Go 简易速速上手小册》第6章:错误处理和测试(2024 最新版)
36 1
|
6天前
|
数据采集 存储 Go
使用Go语言和chromedp库下载Instagram图片:简易指南
Go语言爬虫示例使用chromedp库下载Instagram图片,关键步骤包括设置代理IP、创建带代理的浏览器上下文及执行任务,如导航至用户页面、截图并存储图片。代码中新增`analyzeAndStoreImage`函数对图片进行分析和分类后存储。注意Instagram的反爬策略可能需要代码适时调整。
使用Go语言和chromedp库下载Instagram图片:简易指南
|
1天前
|
Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第23天】Go语言的`context`包提供`Context`接口用于处理任务取消、超时和截止日期。通过传递`Context`对象,开发者能轻松实现复杂控制流。本文解析`context`包特性,讨论常见问题和解决方案,并给出代码示例。关键点包括:1) 确保将`Context`传递给所有相关任务;2) 根据需求选择适当的`Context`创建函数;3) 定期检查`Done()`通道以响应取消请求。正确使用`context`包能提升Go程序的控制流管理效率。
6 1
|
2天前
|
安全 Go 开发者
Golang深入浅出之-Go语言并发编程面试:Goroutine简介与创建
【4月更文挑战第22天】Go语言的Goroutine是其并发模型的核心,是一种轻量级线程,能低成本创建和销毁,支持并发和并行执行。创建Goroutine使用`go`关键字,如`go sayHello(&quot;Alice&quot;)`。常见问题包括忘记使用`go`关键字、不正确处理通道同步和关闭、以及Goroutine泄漏。解决方法包括确保使用`go`启动函数、在发送完数据后关闭通道、设置Goroutine退出条件。理解并掌握这些能帮助开发者编写高效、安全的并发程序。
13 1
|
2天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
3天前
|
Go 开发者
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
【4月更文挑战第21天】本文介绍了Go语言中的流程控制语句,包括`if`、`switch`和`for`循环。`if`语句支持简洁的语法和初始化语句,但需注意比较运算符的使用。`switch`语句提供多分支匹配,可省略`break`,同时支持不带表达式的形式。`for`循环有多种形式,如基本循环和`for-range`遍历,遍历时修改原集合可能导致未定义行为。理解并避免易错点能提高代码质量和稳定性。通过实践代码示例,可以更好地掌握Go语言的流程控制。
11 3
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
|
3天前
|
Go
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
【4月更文挑战第21天】Go语言函数是代码组织的基本单元,用于封装可重用逻辑。本文介绍了函数定义(包括基本形式、命名、参数列表和多返回值)、调用以及匿名函数与闭包。在函数定义时,注意参数命名和注释,避免参数顺序混淆。在调用时,要检查并处理多返回值中的错误。理解闭包原理,小心处理外部变量引用,以提升代码质量和可维护性。通过实践和示例,能更好地掌握Go语言函数。
17 1
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
|
4天前
|
程序员 Go API
【Go语言快速上手(二)】 分支与循环&函数讲解
【Go语言快速上手(二)】 分支与循环&函数讲解
|
4天前
|
Go
Golang深入浅出之-Go语言基础语法:变量声明与赋值
【4月更文挑战第20天】本文介绍了Go语言中变量声明与赋值的基础知识,包括使用`var`关键字和简短声明`:=`的方式,以及多变量声明与赋值。强调了变量作用域、遮蔽、初始化与零值的重要性,并提醒读者注意类型推断时的一致性。了解这些概念有助于避免常见错误,提高编程技能和面试表现。
19 0

热门文章

最新文章