这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记
单元测试
什么是单元测试?
- 首先它是测试==》检测代码正确性
-
其次它是个单元==》粒度最小
-
例如,实现一个加法函数:
-
我们的几个单元测试可以这样进行:
// add.go package main func Add(x, y int) int { return x + y }
// add_test.go
package main
func TestAdd1(t *testing.T) {
x := 1
y := 1
want := 2
got := Add(x, y)
if got != want {
t.Errorf("%d+%d=%d, but %d expected", x, y, got, want)
}
}
为什么我们需要单元测试?
- 万一有bug就完蛋了,测边界值防止意外发生,保证正确性
- 万一你的函数要被重构了,新的函数怎么证明它的正确性,怎么debug
- 钝角
哪里需要单元测试?
- 我就加了一个if,怎么就出bug了(复杂+容易出错)
- 这个库整个公司都在使用,出问题就n+1了(基础代码&公共代码)
- 这个广告计费模块太重要了(重要性)
- 这个需求老变,每次一变我就要改好多单测【这种情况不推荐写单测,因为一改需求就要推倒重来】(基础&底层)
什么时候写单元测试
- 在写代码之前把所有的测试情况想好,测试点就过了就是写好了(难度较高,但是比较流行(TDD))(编码前)
- 写一段,来一个单测,再写一段,再来一个单测(编码中)
- 最后做一个全范围覆盖,补上所有的测试(编码后,大多数人会做的选择)
如何写单元测试
- 在当前package下新建文件add.go,并实现Add函数
// add.go
package main
func Add(x, y int) int {
return x + y
}
- 我们想测试Add函数,那么我们需要在add.go的package下创建add_test.go,并实现逻辑
// add_test.go
package main
func TestAdd1(t *testing.T) {
x := 1
y := 1
want := 2
got := Add(x, y)
if got != want {
t.Errorf("%d+%d=%d, but %d expected", x, y, got, want)
}
}
- 如果我们想并发跑很多case:
// add_test.go
func TestAdd2(t *testing.T) {
type tCase struct {
x int
y int
expected int
}
cases := make([]*tCase, 0, 0)
// test1
cases = append(cases, &tCase{
x: 1,
y: -1,
expected: 0,
})
// test2
cases = append(cases, &tCase{
x: 1,
y: 2,
expected: 3,
})
for i, c := range cases {
t.Run(fmt.Sprintf("case%d", i), func(t *testing.T) {
got := Add(c.x, c.y)
if got != c.expected {
t.Errorf("%d+%d expected %d, but %d got", c.x, c.y, c.expected, got)
}
})
}
}
- mock必不可少
// add_test.go
func init() {
rand.Seed(time.Now().UnixNano())
}
func AddWithRandom(x, y int) int {
return x + y + rand.Int()
}
- mock
random.Int()
func TestAddWithRandom(t *testing.T) {
monkey.Patch(rand.Int, func() int { return 0 })
x := 1
y := 1
expected := 2
got := AddWithRandom(x, y)
if got != expected {
t.Errorf("%d+%d expected %d, but %d got", x, y, expected, got)
}
}
- 基准测试
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
for j := 0; j < 1e9; j++ {
Add(i, i+1)
}
}
}
func BenchmarkMul(b *testing.B) {
for i := 0; i < b.N; i++ {
for j := 0; j < 1e9; j++ {
Mul(i, i+1)
}
}
}