go test单元测试

go test

  • Go语言中的测试依赖go test命令。

  • go test 命令是用来运行测试代码的工具。测试代码通常与要测试的代码放在同一个包中,并且测试文件通常以 _test.go 结尾。

  • go test命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中。

  • 测试文件通常与被测试的代码文件命名相同,但以 _test.go 结尾。例如,如果你有一个名为 math.go 的文件,其测试文件应该命名为 math_test.go

源文件: math.go
测试文件:math_test.go
  • 我们执行go test命令时,它会遍历该go包中所有以_test.go结尾的测试文件, 然后调用并执行测试文件中符合go test 规则的函数帮助我们实现自动化测试。
  • go test测试过程为生成1个临时的main包用于调用相应的测试函数,然后构建并运行测试文件中的函数、报告测试结果,最后清理测试中生成的临时文件。

测试代码结构

*_test.go文件中有三种类型的函数,单元测试函数、基准测试函数和示例函数

类型格式作用
测试函数函数名前缀为Test测试程序的一些逻辑行为是否正确
基准函数函数名前缀为Benchmark测试函数的性能
示例函数函数名前缀为Example为文档提供示例文档

单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

  • 名称以 Test 开头。
  • 接受一个 *testing.T 参数。
  • 没有返回值。
func TestAdd(t *testing.T) {
    // 测试逻辑
}

其中参数t用于报告测试失败和附加的日志信息。 testing.T的拥有的方法如下

在这里插入图片描述

func (c *T) Cleanup(func())           //注册一个清理函数,该函数将在测试函数结束时执行
func (c *T) Error(args ...interface{})//记录一个错误,但不立即停止测试。它相当于 Log 后跟 Fail
func (c *T) Errorf(format string, args ...interface{}) //使用格式化的字符串记录一个错误,但不立即停止测试
func (c *T) Fail()                    //标记当前测试为失败,但不会停止测试函数的执行
func (c *T) FailNow()                 //立即标记当前测试为失败,并停止测试函数的执行
func (c *T) Failed() bool             //返回一个布尔值,指示当前测试是否失败
func (c *T) Fatal(args ...interface{})//记录一个错误,并立即停止测试函数的执行
func (c *T) Fatalf(format string, args ...interface{}) //使用格式化的字符串记录一个错误,并立即停止测试函数的执行
func (c *T) Helper()                  //标记当前函数为测试辅助函数。如果测试失败,堆栈跟踪将从辅助函数开始,而不是从测试函数开始
func (c *T) Log(args ...interface{})  //记录一条日志信息,通常用于调试
func (c *T) Logf(format string, args ...interface{})   //使用格式化的字符串记录一条日志信息
func (c *T) Name() string             //返回当前测试或基准测试的名称
func (c *T) Skip(args ...interface{}) //跳过当前测试,并记录跳过的原因
func (c *T) SkipNow()                 //立即跳过当前测试,并停止测试函数的执行
func (c *T) Skipf(format string, args ...interface{})   //使用格式化的字符串跳过当前测试,并记录跳过的原因
func (c *T) Skipped() bool            //返回一个布尔值,指示当前测试是否被跳过
func (c *T) TempDir() string          //返回一个临时目录的路径,该目录在测试期间存在,并在测试结束时被删除。

基准测试

测试程序执行时间复杂度、空间复杂度

  • 名称以 Benchmark 开头。
  • 接受一个 *testing.B 参数。
  • 没有返回值。
func BenchmarkAdd(b *testing.B) {
    // 基准测试逻辑
}

示例测试

为调用该功能代码的人提供演示

  • 名称以 Example 开头。
  • 没有参数和返回值。
  • 通常包含一个 Output: 注释,表示期望的输出。
func ExampleAdd() {
    // 示例代码
    // Output: 期望的输出
}

测试执行

  • -v:详细输出。
  • -run:运行匹配特定模式的测试函数。
  • -cover:输出测试覆盖率。
  • -bench:运行基准测试。
  • -count:运行测试和基准测试的次数。
# 匹配当前目录下*_test.go命令的文件,执行每一个测试函数
go test -v

# 执行 calc_test.go 文件中的所有测试函数,结尾需要标注原函数
go test -v calc_test.go calc.go

# 指定特定的测试函数(其中:-count=1用于跳过缓存)
go test -v -run TestAdd calc_test.go calc.go -count=1

# 执行基准测试
go test -benchmem -bench 

testing.T

func (c *T) Cleanup(f func())

参数

  • f func(): 一个无参数无返回值的函数,它将在测试函数结束时执行

功能

  • 注册一个清理函数 f,该函数将在当前测试函数结束时自动调用
  • 如果测试函数因为 FailNow()SkipNow() 或 panic 而提前退出,清理函数仍然会被调用

示例

package mypackage
import (
    "io/ioutil"
    "os"
    "testing"
)
func TestCreateAndCleanupFile(t *testing.T) {
    // 创建一个临时文件
    tempFile, err := ioutil.TempFile("", "example")
    if err != nil {
        t.Fatalf("Failed to create temp file: %v", err)
    }
    // 注册清理函数,确保在测试结束后删除临时文件
    t.Cleanup(func() {
        tempFile.Close()
        os.Remove(tempFile.Name())
    })
    // 使用临时文件进行测试
    // ...
}
  • 无论测试成功还是失败,Cleanup(func()) 确保了 tempFile.Close()os.Remove(tempFile.Name()) 会被调用,从而清理了创建的临时文件

注意事项

  • 测试函数执行完毕,没有调用FailNow()SkipNow()或遇到panic,那么注册的清理函数将在测试函数返回之后按注册的逆序执行
  • 测试函数调用了FailNow()或遇到了panic,导致测试提前终止,那么注册的清理函数仍然会在测试终止之前按注册的逆序执行
  • 测试函数调用了SkipNow()Skipf()并被跳过,清理函数同样会在跳过操作之后按注册的逆序执行

func (c *T) Error(args …interface{})

参数

  • args ...interface{}: 可以是任意类型的参数,通常是一个格式化的字符串,用于描述测试失败的原因。

功能

  • 记录错误信息。
  • 标记测试为失败。
  • 继续执行测试函数。

示例

package main

import (
    "testing"
)

// 计算两个整数的和
func add(a, b int) int {
    // 返回两数之和
    return a + b
}


// 测试add函数的正确性
func TestAdd(t *testing.T) {
    // 检查正数相加的情况
    if add(1, 2) != 3 {
        t.Error("两个正数相加的测试失败")
    }

    // 检查负数相加的情况
    if add(-1, -2) != -3 {
        t.Error("两个负数相加的测试失败")
    }
}
  • 如果 Add 函数返回的值与预期不符,t.Error 将被调用以报告错误。测试将继续执行到结束,然后测试框架会报告所有由 Error 方法记录的失败

func (c *****T) Errorf(format string, args **…**interface{})

参数

  • format string: 一个格式化字符串,用于指定错误消息的格式
  • args ...interface{}: 可变数量的参数,它们将被格式化并添加到错误消息中

功能

  • 使用格式化字符串记录错误信息
  • 标记测试为失败
  • 继续执行测试函数

示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Errorf("Add(1, 2) = %d; want 3", sum)
    }
}
func Add(a, b int) int {
    return a + b
}
  • 如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Errorf 方法记录一个格式化的错误消息,并标记测试为失败。测试函数会继续执行,直到 FailNow() 被调用或测试函数的自然结束
  • 使用 Errorf(format string, args ...interface{}) 方法,可以更清晰地报告错误信息,使得测试失败的原因更加直观

func (c *****T) Fail()

功能

  • 标记测试为失败。
  • 继续执行测试函数。

示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
}
func Add(a, b int) int {
    return a + b
}
  • 如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Fail() 方法标记测试为失败。测试函数会继续执行,直到 FailNow() 被调用或测试函数的自然结束

  • 使用 Fail() 方法,可以在测试失败时提供一个简单的标记,而无需记录详细的错误信息。如果需要记录详细的错误信息,可以使用 Errorf(format string, args ...interface{})Error(args ...interface{}) 方法

  • 在 Go 语言的 testing 包中,FailNow() 方法是一个用于立即标记测试失败并停止执行的方法。当测试代码发现一个严重错误时,可以通过调用 FailNow() 来记录错误,并立即停止测试的执行

func (c *T) FailNow()

语法

func (c *T) FailNow()

功能

  • 标记测试为失败。
  • 立即停止测试函数的执行。

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.FailNow()
    }
}
func Add(a, b int) int {
    return a + b
}
  • 在这个例子中,如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.FailNow() 方法标记测试为失败,并立即停止测试的执行。这意味着测试函数中的任何后续代码都不会被执行
  • 使用 FailNow() 方法,可以在遇到严重问题时立即停止测试,避免执行可能会产生更多问题的代码。这种方法通常用于处理测试代码中无法继续执行的情况,例如当依赖的服务不可用或关键资源未正确设置时

func (c *T) Failed() bool

返回值

  • 一个布尔值,如果测试失败,返回 true;否则返回 false

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
    // 检查测试是否失败
    if t.Failed() {
        // 处理测试失败的逻辑
    }
}
func Add(a, b int) int {
    return a + b
}
  • 如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Fail() 方法标记测试为失败。之后,测试函数会调用 t.Failed() 来检查测试是否失败,并根据结果执行相应的逻辑。

  • 使用 Failed() 方法,可以在测试代码中检查测试是否已经失败,并根据测试状态执行不同的逻辑。这有助于在测试失败后进行额外的检查或清理操作。

  • 在 Go 语言的 testing 包中,Fatal(args ...interface{}) 方法是一个用于报告测试失败并立即停止执行的方法。当测试代码遇到一个无法恢复的错误时,可以通过调用 Fatal(args ...interface{}) 来记录错误信息,并立即停止测试的执行

func (c *T) Fatal(args …interface{})

参数

  • args ...interface{}: 可以是任意类型的参数,通常是一个格式化的字符串,用于描述测试失败的原因。

功能

  • 记录错误信息。
  • 标记测试为失败。
  • 立即停止测试函数的执行。

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fatal("Add(1, 2) failed")
    }
}
func Add(a, b int) int {
    return a + b
}
  • 在这个例子中,如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Fatal 方法记录一个错误消息,并立即停止测试的执行
  • 使用 Fatal(args ...interface{}) 方法,可以在遇到无法继续测试的情况时立即停止测试,避免执行可能会产生更多问题的代码。这种方法通常用于处理测试代码中无法恢复的严重错误,例如当关键的依赖服务不可用时

func (c *****T) Fatalf(format string, args **…**interface{})

参数

  • format string: 一个格式化字符串,用于指定错误消息的格式
  • args ...interface{}: 可变数量的参数,它们将被格式化并添加到错误消息中

功能

  • 使用格式化字符串记录错误信息
  • 标记测试为失败
  • 立即停止测试函数的执行

示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fatalf("Add(1, 2) failed with unexpected result: %d", sum)
    }
}
func Add(a, b int) int {
    return a + b
}
  • 如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Fatalf 方法记录一个格式化的错误消息,并立即停止测试的执行。测试函数中的任何后续代码都不会被执行
  • 使用 Fatalf(format string, args ...interface{}) 方法,可以更清晰地报告错误信息,使得测试失败的原因更加直观。当遇到无法继续测试的情况时,Fatalf 是一个非常有用的工具

func (c *****T) Helper()

功能

  • 标记当前函数为测试辅助函数。
  • 如果测试失败,堆栈跟踪将从辅助函数开始。

示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
    // 标记当前函数为辅助函数
    t.Helper()
    // 辅助函数代码
}
func Add(a, b int) int {
    return a + b
}
  • TestAdd 测试函数调用了 t.Helper(),这意味着如果测试失败,堆栈跟踪将从辅助函数开始,而不是从测试函数开始。这有助于开发者更清晰地理解失败的位置,尤其是在使用嵌套的测试函数时。
  • 使用 Helper() 方法,可以在测试函数中定义辅助函数,这些辅助函数可以包含在测试失败时需要执行的代码,如清理操作。通过标记辅助函数,可以避免在测试失败时产生冗长的堆栈跟踪,从而使调试更加容易。

func (c *T) Log(args …interface{})

参数

  • args ...interface{}: 可以是任意类型的参数,通常是一个格式化的字符串,用于描述日志信息。

功能

  • 记录日志信息。
  • 不会停止测试的执行。

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
    // 记录一些日志信息
    t.Log("Add(1, 2) returned", sum)
}
func Add(a, b int) int {
    return a + b
}
  • 如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Fail() 方法标记测试为失败。之后,测试函数会调用 t.Log 方法来记录一些日志信息,这些信息会被输出到测试运行器的标准输出中。
  • 使用 Log(args ...interface{}) 方法,可以在测试过程中记录调试信息或操作步骤,这些信息有助于开发者理解和调试测试代码。

func (c *****T) Logf(format string, args **…**interface{})

参数

  • format string: 一个格式化字符串,用于指定日志消息的格式。
  • args ...interface{}: 可变数量的参数,它们将被格式化并添加到日志消息中。

功能

  • 使用格式化字符串记录日志信息。
  • 不会停止测试的执行。

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
    // 记录一些格式化的日志信息
    t.Logf("Add(1, 2) returned: %d", sum)
}
func Add(a, b int) int {
    return a + b
}
  • 如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Fail() 方法标记测试为失败。之后,测试函数会调用 t.Logf 方法来记录一些格式化的日志信息,这些信息会被输出到测试运行器的标准输出中。
  • 使用 Logf(format string, args ...interface{}) 方法,可以更清晰地记录调试信息或操作步骤,使得日志信息更加易读和易于理解。这有助于开发者理解和调试测试代码。

func (c *T) Name() string

返回值

  • 一个字符串,表示当前测试或基准测试的名称。

示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
}
func Add(a, b int) int {
    return a + b
}
  • TestAdd 测试函数会调用 t.Name() 来获取当前测试的名称。这个名称是在测试函数执行之前由测试运行器指定的,通常与测试文件的名称和测试函数的名称相关联。
  • 使用 Name() 方法,可以在测试代码中根据测试的名称执行特定的逻辑,例如,根据测试的名称选择性地运行某些测试。这有助于在测试框架中实现更复杂的测试逻辑。

func (c *****T) Skip(args **…**interface{})

在 Go 语言的 testing 包中,Skip(args ...interface{}) 方法是一个用于跳过当前测试的方法。当测试代码遇到一个条件,使得当前测试不应该被执行时,可以通过调用 Skip(args ...interface{}) 来跳过当前测试。

语法

func (c *T) Skip(args ...interface{})

参数

  • args ...interface{}: 可以是任意类型的参数,通常是一个格式化的字符串,用于描述跳过测试的原因。

功能

  • 跳过当前测试。
  • 记录跳过测试的原因。

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    // 如果条件不满足,跳过测试
    if condition {
        t.Skip("Skipping test because condition is not met")
    }
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
}
func Add(a, b int) int {
    return a + b
}

在这个例子中,如果 conditiontrueTestAdd 测试函数会使用 t.Skip 方法跳过当前测试,并记录跳过测试的原因。这意味着测试函数中的任何后续代码都不会被执行。
使用 Skip(args ...interface{}) 方法,可以在测试代码中根据特定条件跳过测试,例如,当依赖的服务不可用或关键资源未正确设置时。这有助于确保测试的可重复性和可靠性。

func (c *****T) SkipNow()

在 Go 语言的 testing 包中,SkipNow() 方法是一个用于立即跳过当前测试并停止执行的方法。当测试代码遇到一个条件,使得当前测试不应该被执行时,可以通过调用 SkipNow() 来立即跳过当前测试。

语法

func (c *T) SkipNow()

功能

  • 立即跳过当前测试。
  • 停止测试函数的执行。

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    // 如果条件不满足,立即跳过测试
    if condition {
        t.SkipNow()
    }
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
}
func Add(a, b int) int {
    return a + b
}

在这个例子中,如果 conditiontrueTestAdd 测试函数会使用 t.SkipNow 方法立即跳过当前测试,并停止测试的执行。这意味着测试函数中的任何后续代码都不会被执行。
使用 SkipNow() 方法,可以在测试代码中根据特定条件立即停止测试,避免执行可能会产生更多问题的代码。这种方法通常用于处理测试代码中无法继续执行的情况,例如当关键的依赖服务不可用时。

func (c *****T) Skipf(format string, args **…**interface{})

在 Go 语言的 testing 包中,Skipf(format string, args ...interface{}) 方法是一个用于记录跳过测试原因并立即停止执行的方法。当测试代码遇到一个条件,使得当前测试不应该被执行时,可以通过调用 Skipf(format string, args ...interface{}) 来记录跳过测试的原因,并立即停止测试的执行。

语法

func (c *T) Skipf(format string, args ...interface{})

参数

  • format string: 一个格式化字符串,用于指定跳过测试原因的格式。
  • args ...interface{}: 可变数量的参数,它们将被格式化并添加到跳过测试原因中。

功能

  • 使用格式化字符串记录跳过测试的原因。
  • 立即停止测试函数的执行。

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    // 如果条件不满足,记录跳过测试的原因并立即停止执行
    if condition {
        t.Skipf("Skipping test because condition is not met: %s", reason)
    }
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
}
func Add(a, b int) int {
    return a + b
}

在这个例子中,如果 conditiontrueTestAdd 测试函数会使用 t.Skipf 方法记录一个格式化的跳过测试原因,并立即停止测试的执行。这意味着测试函数中的任何后续代码都不会被执行。
使用 Skipf(format string, args ...interface{}) 方法,可以更清晰地记录跳过测试的原因,使得测试跳过的情况更加直观。当遇到无法继续测试的情况时,Skipf 是一个非常有用的工具。

func (c *****T) Skipped() bool

在 Go 语言的 testing 包中,Skipped() bool 方法是一个用于检查当前测试是否被跳过的辅助函数。通过调用 Skipped(),可以检查测试是否在运行过程中被标记为跳过。

语法

func (c *T) Skipped() bool

返回值

  • 一个布尔值,如果测试被跳过,返回 true;否则返回 false

使用示例

package mypackage
import (
    "testing"
)
func TestAdd(t *testing.T) {
    sum := Add(1, 2)
    if sum != 3 {
        t.Fail()
    }
    // 检查测试是否被跳过
    if t.Skipped() {
        // 处理测试被跳过的逻辑
    }
}
func Add(a, b int) int {
    return a + b
}

在这个例子中,如果 Add 函数的实现不正确,TestAdd 测试函数会使用 t.Fail() 方法标记测试为失败。之后,测试函数会调用 t.Skipped() 来检查测试是否被跳过,并根据结果执行相应的逻辑。
使用 Skipped() 方法,可以在测试代码中检查测试是否已经被跳过,并根据测试状态执行不同的逻辑。这有助于在测试被跳过时进行额外的检查或清理操作。

func (c *T) TempDir() string

返回值

  • 一个字符串,表示当前测试的临时目录路径。

使用示例

package mypackage
import (
    "os"
    "testing"
)
func TestFileOperations(t *testing.T) {
    // 获取当前测试的临时目录
    tempDir := t.TempDir()
    // 在临时目录中创建一个文件
    file, err := os.Create(filepath.Join(tempDir, "temp_file.txt"))
    if err != nil {
        t.Fatal(err)
    }
    defer file.Close()
    // 在临时目录中执行其他操作
    // ...
}

在这个例子中,TestFileOperations 测试函数会调用 t.TempDir() 方法来获取一个唯一的临时目录路径。之后,测试函数会在这个临时目录中创建一个文件,并在执行其他操作时使用这个临时目录。
使用 TempDir() 方法,可以在测试中安全地创建临时文件和目录,这些文件和目录在测试结束后会被自动删除,从而避免了清理工作。这有助于简化测试代码,并确保测试的可重复性。

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值