Go test预判工具Testify
go test
golang
编写测试用例时,首先需要建立以_test
结尾的go文件,这个文件就是专用的测试文件,使用go test
等命令时会执行测试文件中的测试方法。
测试文件中的
- 一般测试:测试方法名需要以大写的
Test
开头,参数为*testing.T
.
func TestSingle(t *testing.T) {
t.Log("log here")
}
- 性能测试:测试方法名需要以大写的
Benchmark
开头,参数为*testing.B
.
func BenchmarkPointerInner(b *testing.B) {
//b.N为循环次数
for i := 0; i < b.N; i++ {
b.Log("log here")
}
}
-
TestMain
方法测试:用于在单元测试前后补充一些操作,测试方法名必须为TestMain
,参数为*testing.M
func TestMain(m *testing.M) {
// call flag.Parse() here if TestMain uses flags
fmt.Println("begin")
m.Run()
fmt.Println("end")
}
编写单元测试时,常会记录一些日志,主要有log
方法,error
方法,fatal
方法,如果error
或者fatal
方法被调用,那么这个单元测试执行结果就是失败的。
func TestSignle(t *testing.T) {
t.Log("test normal log")
t.Error("test error log")
t.Fatal("test fatal log")
}
Testify
Testify
是一个github
上的test
的工具,著名的GIN
框架的单元测试也是使用的它,它能让你的测试代码变得更优雅和高效,测试结果也变得更详细。
测试失败结果:
go mod引入:
require github.com/stretchr/testify v1.4.0
Testify
下主要有三个包assert
、require
、mock
。
-
assert
包用于断言,它会根据输入条件判断,给出错误的。 -
requeire
该包下所包含的方法和assert
相同,只不过当执行失败时,会立刻停止当前单元测试。 -
mock
包用于构造数据
常见例子
以下例子以均以assert
包举例
- Equal操作
func TestAssertEquals(t *testing.T) {
//断言空(最后一个可变参数msgAndArgs 第一个参数是预格式化字符串,后续是响应的值)
assert.Nil(t, nil, "hello:%s, myName is %s", "jim", "zhangsan")
//另一种格式化输出msg
assert.Nilf(t, nil, "hello:%s, myName is %s", "jim", "zhangsan")
//断言相等
assert.Equal(t, 1, 2, "%d is not equals %d", 1, 2)
//断言实际值相等
assert.EqualValues(t, uint32(123), int32(123))
//断言 true
assert.True(t, true)
//断言相等或者实际值箱等, 并带返回结果(true/false)
r1 := assert.ObjectsAreEqualValues(true, false)
t.Log("true is equals false, result is : ", r1)
//断言切片或数组的长度
sc := make([]string, 2)
assert.Len(t, sc, 1, "string slice string len is not 1")
//断言条件
assert.Condition(t, func() bool { return 1 > 2 }, "condition: 1 is not equals 2")
//断言空指针、空切片、空字符串、空信道
assert.Empty(t, []string{}, "array is not empty")
//限时 todo
assert.Eventually(t, func() bool { return true }, 10*time.Second, 10*time.Millisecond)
//断言两个指针所指内容是否是同一个对象
p1:=1
p2:=&p1
assert.Same(t,&p1, p2)
}
- Contains操作
func TestContains(t *testing.T) {
//断言数组A与数组B中所有元素是否互相等于(忽略顺序)
assert.ElementsMatch(t, []string{"hello", "world"}, []string{"world"}, "list a contains list b")
//断言字符串包含(字符串,数组,切片,map)
assert.Contains(t, []string{"Hello", "World"}, "world", "strings contains substr")
//断言数组A是否包含数组B
assert.Subset(t,[]int{1,2},[]int{1})
}
- File操作
func TestAssertFile(t *testing.T){
//断言文件存在
assert.FileExists(t, "/a.txt", "file not exists")
//断言目录存在
assert.DirExists(t, "/hello", "dir is not exists")
}
- Type操作
func TestAssertType(t *testing.T) {
//断言两个对象是相同的类型
assert.IsType(t, (*bytes.Buffer)(nil), &bytes.Buffer{})
//断言继承接口
assert.Implements(t,(*fmt.Stringer)(nil), &bytes.Buffer{})
//断言两个yaml相等
assert.YAMLEq(t,"{name:\n zhangsan}","{#####dddas\n name:\n zhangsan}")
//断言两个json相等
assert.JSONEq(t,"{\"name\":\"zhangsan\"}","{\"name\" : \"zhangsan\"}")
}
- Exception操作
func TestAssertException(t *testing.T) {
//断言会发生panic
fpc := func() {panic(errors.New("panic error"))}
assert.Panics(t,fpc)
//断言会发生panic,并且panic的值相等
fpc1 := func() {panic("new error")}
assert.PanicsWithValue(t,"new error", fpc1)
//输出错误日志
assert.Fail(t, "print error message")
//断言error string相等
assert.EqualError(t, errors.New("err"), "err", "new error string is err")
//断言fail,立刻停止执行测试
assert.FailNow(t,"fail now, next testing will not be exec")
}
- Http操作
func TestAssertHttp(t *testing.T) {
f := func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("goland"))
writer.WriteHeader(http.StatusOK)
}
//断言http body中包含字符串(method,url,values可以自定义传入, writer根据传入参数进行选择并返回)
assert.HTTPBodyContains(t, f, "GET", "www.baidu.com", nil, "goland")
//断言http body中不含字符串
assert.HTTPBodyNotContains(t, f, "GET", "www.baidu.com", nil, "goland")
//断言http请求返回error(400以上)
assert.HTTPError(t, f,"GET","www.baidu.com",nil,"return error")
//断言http请求返回正常(200-206)
assert.HTTPSuccess(t,f,"GET","www.baidu.com",nil)
//断言返回重定向(300-307)
assert.HTTPRedirect(t,f,"GET","www.baidu.com",nil)
}
- Math操作
func TestAssertMath(t *testing.T) {
type Z int
//断言0值
assert.Zero(t, Z(0), "type z(0) value is not 0?")
//断言非0值
assert.NotZero(t, Z(0), "type z(0) value is 0")
//断言大于, 并带返回结果(true/false)
assert.Greater(t,1,2)
//断言大于或者等于, 并带返回结果(true/false)
assert.GreaterOrEqual(t, 1, 2)
//断言小于, 并带返回结果(true/false)
assert.Less(t,2,1)
//断言小于或者等于, 并带返回结果(true/false)
assert.LessOrEqualf(t, 2, 1, "2 is not less equal 1")
//断言两个数字差值不超过指定值
assert.InDelta(t, 0.12346, 0.12345, 0.00001)
//断言多个数字差值不超过指定值(比较的两个map必须有相同的key)
assert.InDeltaMapValues(t,map[string]float32{"1":1.01,"2":2.0},map[string]float32{"1":1.0,"2":2.01},0.01)
//断言多个数字差值不超过指定值(比较的两个切片必须一一对应)
assert.InDeltaSlice(t,[]float32{1,2.01},[]float32{1.01,2},0.01)
//断言两个数字相对差不超过指定值(相对于第一个数)
assert.InEpsilon(t,2.1,2.2,0.1)
//断言两个数字相对差不超过指定值(比较的两个切片必须一一对应)
assert.InEpsilonSlice(t,[]float32{1,2.01},[]float32{1.01,2},0.01)
//断言两个时间点间隔不超过指定时间段
t1:=time.Now()
assert.WithinDuration(t, t1, t1.Add(time.Hour * 8), time.Hour * 9)
//断言正则匹配
assert.Regexp(t,regexp.MustCompile("^it"),"it's starting")
}