青训营 X 豆包MarsCode 技术训练营 | Go语言工程实践之测试

281 阅读4分钟

补一下跟青训营学习的过程

单元测试

  • 单元测试位于测试的最底层,是开发者对于单独的模块进行测试,覆盖率最大,测试成本最低,但是决定代码质量最重要的一环。通过测试单元的输出与期望值进行校对从而验证代码的正确性,从而保证新旧代码的互不影响与程序的正常运行。

单元测试规则

  1. 测试文件以_test.go结尾

  2. 测试函数以Test开头

  3. 测试函数的参数为t *testing.T

  4. 测试函数的返回值为void

  5. 初始化逻辑放到TestMain函数中

  6. 测试函数的执行顺序是随机的

  7. 测试函数的执行顺序是按照测试文件的顺序执行的

  8. 测试函数的执行顺序是按照测试函数的顺序执行的

  • 演示
func TestMain(m \*testing.M) {
        // 测试前:数据装载、配置初始化
        code := m.Run()
        // 测试后:数据清理、配置还原
        os.Exit(code)
        }
package unittest

import (
	"testing"
)

func HelloTom() string {
	return "Jerry"
}

func TestHelloTom(t *testing.T) {
	output := HelloTom()
	expectedOutput := "Tom"
	if output != expectedOutput {
		t.Errorf("Expected output %s, but got %s.", expectedOutput, output)
	}
}
// 命令行执行go test -v hellotom_test.go

预期执行结果

test1.png

单元测试-assert

除去使用简单的'!='来判断,也同样可以使用第三方库testify中的 assert 操作
直接导入相应的库

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

在testify导入时可能会报错could not import github.com/stretchr/testify/assert (no required module...),此时就需要通过go get指令来获得相应的库
命令行输入

go get -u -v github.com/stretchr/testify/assert

终端会有如下响应

go: downloading github.com/stretchr/testify v1.9.0
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/pmezard/go-difflib v1.0.0
go: added github.com/davecgh/go-spew v1.1.1
go: added github.com/pmezard/go-difflib v1.0.0
go: added github.com/stretchr/testify v1.9.0
go: added gopkg.in/yaml.v3 v3.0.1

之后就可以使用assert操作完成相应的单元测试

  • 演示
package unittest

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

func HelloTom() string {
	return "Jerry"
}
func TestHelloTom(t *testing.T) {
	output := HelloTom()
	expectedOutput := "Tom"
	assert.Equal(t, expectedOutput, output, "They shoule be equal")
}
// 命令行执行go test hellotom_test.go

预期执行结果

test2.png 可以看到经过assert操作,命令行可以返回更加详细的报错信息,例如我们预期输出(expected)为"Tom",实际输出(actual)为"Jerry",此时就需要进行相应修改

单元测试-覆盖率

  • 衡量代码是否经过了足够的测试
  • 评价项目的测试水准
  • 评估项目是否达到了高水准测试等级

演示

package unittest

func JudgePassLine(score int16) bool {
	if score >= 60 {
		return true
	}
	return false
}
package unittest

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


func TestJudgePassLine(t *testing.T) {
	isPass := JudgePassLine(70)
	assert.Equal(t, true, isPass)
}
// 命令行执行go test judgepassline_test.go judgepassline.go --cover

预期输出

testcover.png

其中66.7%的覆盖率是因为在judgepassline.go中从if条件判断开始执行,直到return true后便不再执行,没有执行最后的return false,也就是说三行代码执行了两行,所以测试覆盖率为2/3=66.7%。

实际应用

在跟青训营做一个基于Gin高性能的go web框架,主要实现的功能是对某一话题下回帖内容的查询。在进行相关repository实现的内存索引过程中,涉及到了初始化回帖列表索引数据函数initPostIndexMap,它的作用是将post按照parent_id顺序添加在post列表中,在对post列表进行初始化添加时,缺少了一句相关代码,post列表理想初始化情况为每一个topicId下对应5个post,而因为缺少了一行代码,导致了post列表初始化后仅有一个元素。测试函数如下图所示

单元测试用例.png
首先通过TestMain来测试repository是否能正确初始化,然后通过TestQueryPageInfo来测试帖子的查询功能是否正确,以id=1来测试,assert.NotEqual()来判断pageInfo是否正确初始化,再通过assert.Equal()来判断id=1的topic下postList是否正确初始化,预期值为5,然而通过下图可以看出assert操作测试得到结果为1,证明我们postList初始化发生了错误

assert实际应用.png 此时不信邪,继续开发的话,直到最后项目的repository、service、controller还有最后的外部接口都编写完毕后,运行项目,通过在命令行输入相关curl命令去访问该页面信息,会得到如下反馈

service实际运行结果.png

可以看到,确实有topic以及相关postList的信息反馈,但是postList的元素仅有一个,和我们之前通过TestQueryPageInfo来测试初始化回帖列表元素是否正常运行的结果是对应的(即上一张图中的expected:5 actual:1) ,后续就是通过delve对代码的调试,让get命令成功读取到5个post
在初学的小项目中,assert可以实现一些核心功能的测试,图片来看是非常直观的,也算是加深了对于单元测试的一些理解