关于 Go 的基本语法,参见:半天时间 Go 语言的基本实践
单元测试
Go 中提供了 testing
这个 package 和 go test
这个命令来进行单元测试。
假设我们要创建一个数学运算的 package,名字叫 algo
,提供了加法运算 add()
和减法运算 sub()
。
首先我们创建一个 algo
的文件夹,在里面创建一个 add.go
文件和 sub.go
文件,分别如下:
package algo
func add(x int, y int) int {
return x + y
}
package algo
func sub(x int, y int) int {
return x - y
}
现在我们要对 add()
和 sub()
方法进行单元测试,需要有如下几步:
- 创建一个测试文件,文件名以
XXX_test.go
结尾,例如algo_test.go
- 该测试文件放在被测试文件相同的 package 中:
package algo
- Go doesn't ship your tests。该测试文件不会会编译器放到编译后的 Binary 中
- 该测试文件放在被测试文件相同的 package 中:
- 导入
testing
这个 package:import "testing"
- 创建方法
func TestXxx(t *testing.T)
,在这里面定义测试:func TestAdd(t *testing.T)
func TestSub(t *testing.T)
- 使用
t.Error
,t.Fail
等方法来标记测试错误- 可以使用
t. Errorf
来打印详情 - 可以使用
t.Log
来打印日志文件
- 可以使用
- 最后使用
go test
命令来执行单元测试
我们创建 algo_test.go
测试文件如下:
package algo
import "testing"
func TestAdd(t *testing.T) {
want := 3
got := add(1, 2)
if got != want {
t.Errorf("add was incorrect, got: %d, want: %d.", got, want)
}
}
func TestSub(t *testing.T) {
want := -1
got := sub(1, 2)
if got != want {
t.Errorf("sub was incorrect, got: %d, want: %d.", got, want)
}
}
最后使用 go test
命令来执行单元测试:
如果我们故意把 sub
方法写错,go test
命令会标记测试错误:
如何创建多个测试用例?
在上述的代码中,我们为 add()
方法只创建了一个测试用例 add(1, 2) = 3
。
我们可以通过 Go 中的 slice
来创建多个测试用例:
func TestAdd(t *testing.T) {
cases := []struct {
p1 int
p2 int
want int
} {
{p1: 1, p2: 2, want: 3},
{p1: 3, p2: 4, want: 7},
{p1: 5, p2: 6, want: 11},
}
for _, tc := range cases {
got := add(tc.p1, tc.p2)
if got != tc.want {
t.Errorf("add was incorrect, got: %d, want: %d.", got, tc.want)
}
}
}
如何得到语句覆盖率
使用 go test -cover
命令:
Mockup 依赖
假设我们的 add()
方法在返回 x + y
的时候,需要再乘以一个系数,这个系数通过一个服务得到。
- 这个服务对应的接口叫做
ParamServiceInterface
。 - 这个服务的真正实现叫做
ParamServiceImpl
。
package algo
type ParamServiceInterface interface {
getParam() int
}
type ParamServiceImpl struct {
// 依赖的一些其他 service
}
func (impl ParamServiceImpl) getParam() int {
// 复杂的计算逻辑
// return ....
return 1
}
func add(x int, y int, paramService ParamServiceInterface) int {
return paramService.getParam() * (x + y)
}
我们在做单元测试的时候,无法得到实现类 ParamServiceImpl
来传入 add()
方法。
因此可以 Mock 出一个服务,代码如下:
type ParamServiceFake struct {
param int
}
func (fake ParamServiceFake) getParam() int {
return fake.param
}
func TestAdd(t *testing.T) {
cases := []struct {
p1 int
p2 int
fake ParamServiceFake
want int
} {
{p1: 1, p2: 2, fake: ParamServiceFake{1}, want: 3},
{p1: 3, p2: 4, fake: ParamServiceFake{2}, want: 14},
{p1: 5, p2: 6, fake: ParamServiceFake{3}, want: 33},
}
for _, tc := range cases {
got := add(tc.p1, tc.p2, tc.fake)
if got != tc.want {
t.Errorf("add was incorrect, got: %d, want: %d.", got, tc.want)
}
}
}
引用:
testing - The Go Programming Language