1. 为什么需要断言库?
官方说法:Go不提供断言,我们知道这会带来一定的不便,其主要目的是为了防止你们这些程序员在错误处理上偷懒。 引入断言能为我们提供便利——提高测试效率,增强代码可读性。
testify是用go实现的一个assert风格的测试框架,这个包提供了我们需要的断言的功能,提供了非常丰富的断言方法,使用起来非常简单且易于理解。
2. 如何使用testify进行断言?
- 安装
go get github.com/stretchr/testify
2.Quick start
代码语言:txt复制package algo
import (
"github.com/stretchr/testify/assert"
"testing"
)
/**
* @Description
* @Author guirongguo
* @Email 3095764372@qq.com
* @Date 2021/8/30 23:00
**/
// 简单使用
func TestSimpleRand(t *testing.T) {
t.Log("start ...")
assert := assert.New(t)
assert.Equal(1, 1)
assert.NotEqual(1, 2)
assert.NotNil("123")
assert.IsType([]string{}, []string{""})
assert.Contains("Hello World", "World")
assert.Contains(map[string]string{"Hello": "World"}, "Hello")
assert.Contains([]string{"Hello", "World"}, "Hello")
assert.True(true)
assert.True(false)
t.Log("next ...")
var s []string
assert.Empty(s)
assert.Nil(s)
t.Log("end ...")
}
// 一般用的更多的是表驱动方式把同一个单元的测试用例都放在一起
func TestCalculate(t *testing.T) {
assert := assert.New(t)
var tests = []struct {
input int
expected int
}{
{2, 4},
{-1, 1},
{0, 2},
{-5, -3},
{99999, 100001},
}
for _, test := range tests {
assert.Equal(Calculate(test.input), test.expected)
}
}
运行结果
代码语言:txt复制=== RUN TestSimpleRand
simple_random_test.go:16: start ...
simple_random_test.go:27:
Error Trace: simple_random_test.go:27
Error: Should be true
Test: TestSimpleRand
simple_random_test.go:28: next ...
simple_random_test.go:32: end ...
--- FAIL: TestSimpleRand (0.00s)
=== RUN TestCalculate
simple_random_test.go:50:
Error Trace: simple_random_test.go:50
Error: Not equal:
expected: 1
actual : 4
Test: TestCalculate
simple_random_test.go:50:
Error Trace: simple_random_test.go:50
Error: Not equal:
expected: -2
actual : 1
Test: TestCalculate
simple_random_test.go:50:
Error Trace: simple_random_test.go:50
Error: Not equal:
expected: -1
actual : 2
Test: TestCalculate
simple_random_test.go:50:
Error Trace: simple_random_test.go:50
Error: Not equal:
expected: -6
actual : -3
Test: TestCalculate
simple_random_test.go:50:
Error Trace: simple_random_test.go:50
Error: Not equal:
expected: 99998
actual : 100001
Test: TestCalculate
--- FAIL: TestCalculate (0.00s)
Expected :99998
Actual :100001
<Click to see difference>
FAIL
可以看到断言失败会抛出错误信息,并且继续执行后面的断言。
3. suite套件包
github.com/stretchr/testify/suite 提供了测试套件功能,可以在整个套件开始结束时执行动作,也可以在每个测试开始结束时执行动作。用法如下:
代码语言:txt复制package algo
import (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"testing"
)
/**
* @Description
* @Author guirongguo
* @Email 3095764372@qq.com
* @Date 2021/8/30 23:00
**/
type _Suite struct {
suite.Suite
}
// SetupSuite() 和 TearDownSuite() 全局只会执行一次
// SetupTest() TearDownTest() BeforeTest() AfterTest() 对套件中的每个测试执行一次
func (s *_Suite) AfterTest(suiteName, testName string) {
fmt.Printf("AferTest: suiteName=%s,testName=%sn", suiteName, testName)
}
func (s *_Suite) BeforeTest(suiteName, testName string) {
fmt.Printf("BeforeTest: suiteName=%s,testName=%sn", suiteName, testName)
}
// SetupSuite() 仅执行一次
func (s *_Suite) SetupSuite() {
fmt.Printf("SetupSuite() ...n")
}
// TearDownSuite() 仅执行一次
func (s *_Suite) TearDownSuite() {
fmt.Printf("TearDowmnSuite()...n")
}
func (s *_Suite) SetupTest() {
fmt.Printf("SetupTest()... n")
}
func (s *_Suite) TearDownTest() {
fmt.Printf("TearDownTest()... n")
}
func (s *_Suite) TestSimpleRand() {
fmt.Printf("TestSimpleRand()... n")
ret := SimpleRand(1, 10) // 4.
assert.Equal(s.T(), ret, int64(10))
}
func (s *_Suite) TestCalculate() {
fmt.Printf("TestCalculate()... n")
ret := Calculate(1) //9.
assert.Equal(s.T(), ret, 0)
}
// 让 go test 执行测试
func TestAll(t *testing.T) {
suite.Run(t, new(_Suite))
}
运行结果
代码语言:txt复制GOROOT=/usr/local/go #gosetup
GOPATH=/Users/guirong/go #gosetup
/usr/local/go/bin/go test -c -o /private/var/folders/kk/5llx7c2j0r90sp2hhlptlc1m0000gn/T/____Suite_in_testcase_demo_cmd_algo testcase-demo/cmd/algo #gosetup
/usr/local/go/bin/go tool test2json -t /private/var/folders/kk/5llx7c2j0r90sp2hhlptlc1m0000gn/T/____Suite_in_testcase_demo_cmd_algo -test.v -test.run ^QTestAllE$ -testify.m ^TestSimpleRand|TestCalculate$
=== RUN TestAll
SetupSuite() ...
--- PASS: TestAll (0.00s)
=== RUN TestAll/TestCalculate
SetupTest()...
BeforeTest: suiteName=_Suite,testName=TestCalculate
TestCalculate()...
AferTest: suiteName=_Suite,testName=TestCalculate
TearDownTest()...
--- PASS: TestAll/TestCalculate (0.00s)
=== RUN TestAll/TestSimpleRand
SetupTest()...
BeforeTest: suiteName=_Suite,testName=TestSimpleRand
TestSimpleRand()...
AferTest: suiteName=_Suite,testName=TestSimpleRand
TearDownTest()...
TearDowmnSuite()...
--- PASS: TestAll/TestSimpleRand (0.00s)
PASS
Process finished with exit code 0