52周学技术系列:Go语言单元测试实战指南

52周学技术系列:Go语言单元测试实战指南

52-technologies-in-2016 Let's learn a new technology every week. A new technology blog every Sunday in 2016. 52-technologies-in-2016 项目地址: https://gitcode.com/gh_mirrors/52/52-technologies-in-2016

前言

在软件开发过程中,单元测试是保证代码质量的重要手段。Go语言作为一门现代化的编程语言,内置了强大的测试支持。本文将深入探讨如何在Go语言中进行单元测试,通过实际案例演示测试的编写方法和最佳实践。

Go测试基础

测试文件命名规范

在Go语言中,测试文件需要遵循特定的命名规范:

  • 测试文件必须命名为<被测试文件名>_test.go
  • 例如,要测试calculator.go,测试文件应命名为calculator_test.go

测试函数结构

测试函数需要满足以下要求:

  1. 函数名必须以Test开头
  2. 接收一个*testing.T类型的参数
  3. 无返回值
func TestAdd(t *testing.T) {
    // 测试逻辑
}

简单测试示例

让我们从一个简单的例子开始。假设我们有一个判断三个数是否相等的函数:

package problems

func EqualOrNotEqual(first, second, third int) bool {
    return first == second && second == third
}

对应的测试文件可以这样写:

package problems

import "testing"

func TestEqualOrNotEqual_AllEqual(t *testing.T) {
    result := EqualOrNotEqual(1, 1, 1)
    if !result {
        t.Error("期望true,实际得到", result)
    }
}

测试运行与报告

运行测试

Go提供了简单的命令来运行测试:

go test

常用选项:

  • -v:显示详细输出
  • -run:运行特定测试(支持正则表达式)
  • -count:重复运行测试次数

测试输出优化

可以通过t.Logt.Logf方法输出更详细的测试信息:

func TestEqualOrNotEqual_AllEqual(t *testing.T) {
    t.Log("测试三个相等数字的情况")
    result := EqualOrNotEqual(1, 1, 1)
    if !result {
        t.Error("\t期望true,实际得到", result)
    } else {
        t.Log("\t测试通过")
    }
}

使用-v选项运行可以看到这些日志信息。

高级测试技巧

表格驱动测试

表格驱动测试是Go中常用的测试模式,可以避免重复代码:

func TestEqualOrNotEqual_Table(t *testing.T) {
    tests := []struct {
        name   string
        a, b, c int
        want   bool
    }{
        {"三个相等", 1, 1, 1, true},
        {"两个相等", 1, 1, 2, false},
        {"都不相等", 1, 2, 3, false},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := EqualOrNotEqual(tt.a, tt.b, tt.c)
            if got != tt.want {
                t.Errorf("EqualOrNotEqual(%d, %d, %d) = %v, 期望 %v", 
                    tt.a, tt.b, tt.c, got, tt.want)
            }
        })
    }
}

使用断言库

虽然Go标准库没有提供断言功能,但可以使用第三方库如testify/assert

import "github.com/stretchr/testify/assert"

func TestEqualOrNotEqual_WithAssert(t *testing.T) {
    assert.True(t, EqualOrNotEqual(1, 1, 1), "三个1应该返回true")
    assert.False(t, EqualOrNotEqual(1, 2, 3), "1,2,3应该返回false")
}

黑盒测试与白盒测试

Go支持两种测试方式:

  1. 白盒测试:测试代码与被测代码在同一个包,可以访问非导出成员
  2. 黑盒测试:测试代码在被测包的_test包中,只能访问导出成员

黑盒测试示例:

package problems_test

import (
    "testing"
    . "github.com/shekhargulati/problems"
)

func TestEqualOrNotEqual_BlackBox(t *testing.T) {
    // 只能调用导出的EqualOrNotEqual函数
}

实际案例:最近数字对

让我们看一个更复杂的例子:查找数组中最近的两个数字。

实现代码:

package problems

import (
    "math"
    "sort"
)

type Pair struct {
    First, Second int
}

func ClosestPair(numbers []int) Pair {
    sort.Ints(numbers)
    var pair Pair
    minDiff := math.MaxInt32
    
    for i := 0; i < len(numbers)-1; i++ {
        diff := numbers[i+1] - numbers[i]
        if diff < minDiff {
            minDiff = diff
            pair = Pair{numbers[i], numbers[i+1]}
        }
    }
    return pair
}

测试代码:

package problems_test

import (
    . "github.com/shekhargulati/problems"
    "github.com/stretchr/testify/assert"
    "testing"
)

func TestClosestPair(t *testing.T) {
    tests := []struct {
        name string
        in   []int
        want Pair
    }{
        {"常规情况1", []int{2, 10, 5, 6, 15}, Pair{5, 6}},
        {"常规情况2", []int{2, 4, 5}, Pair{4, 5}},
        {"包含大数", []int{100, 5, 7, 99, 11}, Pair{99, 100}},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := ClosestPair(tt.in)
            assert.Equal(t, tt.want.First, got.First)
            assert.Equal(t, tt.want.Second, got.Second)
        })
    }
}

测试覆盖率

Go可以生成测试覆盖率报告:

go test -cover
go test -coverprofile=coverage.out
go tool cover -html=coverage.out

测试最佳实践

  1. 测试命名:测试函数名应清晰表达测试意图
  2. 表格驱动:对多组输入输出使用表格驱动测试
  3. 子测试:使用t.Run组织相关测试
  4. 错误信息:提供足够的信息帮助定位问题
  5. 边界条件:特别注意边界条件的测试
  6. 并行测试:对于独立测试可以使用t.Parallel()

总结

Go语言的测试框架虽然简单,但功能强大。通过本文的介绍,我们了解了:

  • Go测试的基本结构和运行方式
  • 表格驱动测试的实现
  • 断言库的使用
  • 黑盒与白盒测试的区别
  • 测试覆盖率分析
  • 实际案例的测试方法

良好的测试习惯是成为优秀Go开发者的重要一环。希望本文能帮助您掌握Go语言单元测试的核心技巧,为编写更健壮的Go代码打下坚实基础。

52-technologies-in-2016 Let's learn a new technology every week. A new technology blog every Sunday in 2016. 52-technologies-in-2016 项目地址: https://gitcode.com/gh_mirrors/52/52-technologies-in-2016

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张姿桃Erwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值