Golang测试入门 | 青训营

125 阅读3分钟

规范

  1. 测试文件已_test.go结尾
  2. 单元测试:func TestXxx(*testing.T) 基准测试:func BenchmarkXxx
  3. 如果有初始化逻辑,放到TestMain()中

单元测试

运行测试指令

go test [flag] [packages]

可用assert包进行声明以检测结果的正确性

go get github.com/stretchr/testify/assert

image.png

评估测试效果——Coverage

代码覆盖率是指测试用例是否覆盖了被测试代码的全部语句、分支、函数、行数等。通过评估代码覆盖率,可以判断测试用例是否充分覆盖了被测试代码,进而评估测试效果。在Golang中,可以使用go test命令的--cover标志来计算代码覆盖率。

原理是啥?

在网上搜索了相关问题,这里做一个总结:

在 Golang 中,代码覆盖率的计算是通过在编译时插入特殊的指令来实现的,这些指令在程序运行时会被触发,从而统计出代码的覆盖率。

具体来说,编译器会在每个基本块的开头插入一个指令,这个指令会将基本块的信息(如起始位置和长度)写入一个表格中。程序运行时,会记录每个基本块是否被执行过,最后根据表格中的信息计算出代码的覆盖率。因此,在编写测试用例时,需要尽可能地覆盖被测试代码的所有分支和语句,以保证测试的充分性和准确性。

一般来说,50%~60%是正常需要的覆盖度。较好的是80%+

Mock

Mock是一种模拟测试方式,它通过模拟依赖项的行为来使测试更加可控和可靠。在Golang中,常用的Mock框架包括gomock和testify/mock和nouk/monkey。Mock可以用于模拟外部服务,或者用于模拟复杂的对象,在测试中有效地隔离被测试对象的依赖项,从而更好地进行单元测试。

这里讲一下bouk/monkey。

使用bouk/monkey进行模拟测试

bouk/monkey允许我们在运行时替换任何函数或者变量,这样我们就可以从依赖项中隔离地测试代码。

安装:

go get -u github.com/bouk/monkey

安装完成后,导入包后,就可以在测试中调用patch函数**(课程里说的打桩)**,并传递要替换的函数或变量以及替换函数或变量。下面我写了一个示例:

func TestMyFunction(t *testing.T) {
    // 用始终返回相同时间的函数替换time.Now
    patch := monkey.Patch(time.Now, func() time.Time {
        return time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)
    })
    defer patch.Unpatch()

    // 现在,调用time.Now将始终返回相同的时间
    result := MyFunction()
    expected := "2022-01-01T00:00:00Z"
    if result != expected {
        t.Errorf("期望%s,但得到%s", expected, result)
    }
}

在此示例中,我们测试了MyFunction,函数调用time.Now。通过使用bouk/monkeytime.Now替换为始终返回相同时间的函数,我们可以在隔离的情况下测试MyFunction,而不必担心当前时间的更改会影响结果。

应在测试完成后调用Unpatch以恢复原始函数或变量!可用defer。

课程中提到了Patch和UnPatch的原理:

image.png

本质上是通过reflect包来替换内存地址,很容易理解。

基准测试 benchmark

基准测试是一种评估代码性能的方式,用于衡量某个函数或算法的运行时间。基准测试有助于优化代码性能,特别是在涉及计算密集型操作或需要优化的代码块中。

用得上的方法:

b.ResetTimer()

指令:

go test -bench=.

例子:


// sum.go
package main

func Sum(numbers []int) int {
    sum := 0
    for _, num := range numbers {
        sum += num
    }
    return sum
}

// sum_test.go
package main

import (
    "testing"
)

// 基准测试函数
func BenchmarkSum(b *testing.B) {
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    for i := 0; i < b.N; i++ {
        Sum(numbers)
    }
}