Go工程进阶(2):测试和项目实战 | 青训营笔记

36 阅读2分钟

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

1.测试

测试可大致分为三类:回归测试,集成测试,单元测试
从前到后,覆盖层逐层变大,成本逐层降低。

1.1 回归测试

1.2 集成测试

1.3 单元测试

单元测试流程

单元测试1.png
优点:保证质量,提升效率

单元测试规则:

单元测试2.png

  • 一般覆盖率:50%-60%,较高覆盖率80%+
  • 测试分支相互独立、全面覆盖
  • 测试单元粒度足够小,函数单一职责

单元测试-依赖

单元测试3.png

单元测试-文件处理

一个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了。

单元测试-Mock

快速Mock函数:

  • 为一个函数打桩
  • 为一个方法打桩
// 用函数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
// 这样整个测试函数就摆脱了本地文件的束缚和依赖

2.项目实战

需求:社区话题页面

  • 实现一个展示话题(标题,文字描述)和回帖列表的后端http接口;
  • 本地文件存储数据(暂不考虑前端页面实现,仅实现一个本地web服务)
  • 话题和回帖数据用文件存储

组件及技术点

  • web框架:Gin - github.com/gin-gonic/g… 了解go web框架的简单使用
  • 分层结构设计:github.com/bxcodec/go-… 了解分层设计的概念
  • 文件操作:读文件pkg.go.dev/io
  • 数据查询:索引www.baike.com/wikiid/5527…