Go 语言工程实践之测试| 青训营笔记

204 阅读3分钟

这是我参与「第五届青训营」伴学笔记创作活动的第5天

image.png 今天复习总结的内容是之前学过的Go 语言工程实践之测试相关的内容。

Go 语言工程实践之测试

测试关乎产品的质量安全。因此产品测试是生产产品中的重要一环 。

相关事故:

image.png

image.png 测试可以说是避免事故的最后一道屏障。

单元测试

image.png 单元测试包括:输入、输出、测试单元、期望与输出的校对

单元测试的相关规则

image.png

  • 所有测试文件以_test.go结尾
  • func Test(* testing.T)
  • 初始化逻辑放到TestMain中

单元测试 例子

import(
    "github.com/stretchr/testify/assert"
    "testing"
)
​
func TestHelloTom(t *testing.T) {
    output := HelloTom()
    expectOutput := "Tom"
    assert.Equal(t, expectOutput, output)
}
​
func HelloTom() string {
    return "Tom"
}

image.png

覆盖率

覆盖率出现的目的:

  • 衡量代码是否经过了足够的测试
  • 评价项目的测试水准
  • 评估项目是否达到了高水准测试等级
func JudgePassLine(score int16) bool {
    if score >= 60 {
        return true
    }
    else {
        return false
    }
}
​
// judgment_test.go
func TestJudgePassLineTrue(t *testing.T) {
    isPass := JudgeePassLine(70)
    assert.Equal(t, true, isPass)
}
​
func TestJudgePassLineFalse(t *testing.T) {
    isPass := JudgeePassLine(50)
    assert.Equal(t, false, isPass)
}
​
/*
 通过go test 命令测试覆盖率
*/

image.png

image.png

依赖

image.png

  • 幂等:重复运行同一个case,结果与之前一致
  • 稳定:指单元测试相互隔离,可以独立运行

文件处理

当测试文件被修改后,可能会导致测试失败或错误率增高,从而出现了Mock函数

func ReadFirstLine() string {
    open, err := os.Open("log") // 打开一个文件
    defer open.Close()
    if err != nil {
        return ""
    }
    scanner := bufio.NewScanner(open) // 对每行进行遍历
    for scanner.Scan() {
        return scanner.Text()
    }
    return ""
}
​
func ProcessFirstLine() string {
    line := ReadFirstLine()
    destLine := strings.ReplaceAll(line, "11", "00") // 替换11为00
    return destLine
}
​
func TestProcessFirstLine(t *testing.T) { // 执行单元测试
    firstLine := ProcessFirstLine()
    assert.Equal(t, "line00", firstLine)
}

Mock测试

monkey: github.com/bouk/monkey 这是一个开源的mock测试库,可以对method或者实例的方法进行mock

Monkey Patch的作用域在Runtime, 运行时通过Go的unsafe包能够将内存中函数的地址替换为运行时函数的地址,将待打桩函数或方法的实现跳转。

// 用函数A去替换函数B,B就是原函数,A就是打桩函数func Patch(target, replacement interface{}) *PatchGuard {
    // target就是原函数,replacement就是打桩函数
    t := reflect.ValueOf(target)
    r := reflect.ValueOf(replacement)
    patchValue(t, r)
    return &PatchGuard{t, r}
}
​
func Unpatch(target interface{}) bool {
    // 保证了在测试结束之后需要把这个包卸载掉
    return unpatchValue(reflect.ValueOf(target))
}
​
func TestProcessFirstLineWithMock(t *testing.T) {
    monkey.Patch(ReadFirstLine, func() string {
        return "line110"
    })
    defer monkey.Unpatch(ReadFirstLine)
    line := ProcessFirstLine()
    assert.Equal(t, "line000", line)
}
// 通过patch对ReadFirstLine进行打桩mock,默认返回line110,通过defer卸载mock
// 这样整个测试函数就摆脱了本地文件的束缚和依赖

基准测试

基准测试是指测试一段程序的性能及耗费CPU的程度;

在实际的项目开发中,经常会遇到代码性能瓶颈,为了定位问题,经常要对代码做性能分;

这时就用到了基准测试,其使用方法与单元测试类似。

  • 优化代码,需要对当前代码分析
  • 内置的测试框架提供了基准测试的能力