Golang unittest package使用案例
Unittest框架: testing vs testify
testify | testing | |
---|---|---|
基本信息 | 一组 golang 包,其中包含许多用于测试 Go 代码的工具。Testify 是一个 Go 测试框架,具有一些出色的功能,例如更简单的断言、测试套件接口和 Mocks | go test是一个内置的工具/命令,用于在 Golang 中进行自动化测试,而 test 是内置的测试库测试是随 go 一起提供的包,与 go test 命令结合以提供最小但完整的测试体验 |
服务端 | 是 | 是 |
fixture增量 | 否 | 是。go test原生支持可忽略 $GOPATH 中以“testdata”一词开头、以句点或下划线开头的任何目录 |
Licence | MIT | MIT |
Mocks | 提供“mock”包具有一种可以轻松编写用于代替真实对象的模拟对象的机制 | 与测试库集成良好的第三方库GoMock |
Group | 使用“suite”包,开发人员可以构建一个测试套件作为结构构建拆卸和设置方法以及结构上的测试方法,然后使用“go test”运行它们 | 使用Map测试,这是用最少的代码对函数或行为执行多个 I/O 测试的好方法 |
testing
是golang
官方提供的测试包.高性能,无外部依赖。 唯一缺憾是缺少assert
断言判断类和方法,冥冥之中加大了unittest
的判断数量和代码行。testify
是 用是golang
实现的一个assert
风格的测试框架,这个包提供了我们需要的断言的功能,提供了非常丰富的断言方法,使用起来非常简单且易于理解。
testify包使用
testify
核心有三部分内容: 其中 require
已废弃
- assert: 断言. 包括
Equal
、Nil
、Error
deng - mock: mock测试. 包括
http mock
、object mock
、method mock
等 - suite: 测试套件. 包括
SetupSuite
、SetupTest
、BeforeTest
、AfterTest
、TearDownTest
、TearDownSuite
assert使用
package utils
import (
"testing"
"github.com/stretchr/testify/assert"
)
// 简单使用方式
func TestMd5Encode(t *testing.T) {
assert := assert.New(t)
assert.Equal("74b87337454200d4d33f80c4663dc5e5", Md5Encode("aaaa"), "is not equal")
}
// Map驱动方式
func TestEqual(t *testing.T) {
assert := assert.New(t)
var tt = []struct {
input int
expected int
}{
{2, 4},
{1, 1},
{0, 0},
{-5, 5},
{99999, 99999},
}
for _, t := range tt {
assert.Equal(t.input, t.expected)
}
}
mock使用
package api
import (
"testing"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type prepareSlotMock struct {
mock.Mock
}
func (m *prepareSlotMock) Order() uint32 {
return 0
}
func (m *prepareSlotMock) Prepare(ctx *base.EntryContext) {
m.Called(ctx)
return
}
func Test_entryWithArgsAndChainPass(t *testing.T) {
sc := base.NewSlotChain()
ps1 := &prepareSlotMock{}
rcs1 := &mockRuleCheckSlot1{}
rcs2 := &mockRuleCheckSlot2{}
ssm := &statisticSlotMock{}
sc.AddStatPrepareSlot(ps1)
sc.AddRuleCheckSlot(rcs1)
sc.AddRuleCheckSlot(rcs2)
sc.AddStatSlot(ssm)
// method mock
ps1.On("Prepare", mock.Anything).Return()
rcs1.On("Check", mock.Anything).Return(base.NewTokenResultPass())
rcs2.On("Check", mock.Anything).Return(base.NewTokenResultPass())
ssm.On("OnEntryPassed", mock.Anything).Return()
ssm.On("OnCompleted", mock.Anything).Return()
entry, b := entry("abc", &EntryOptions{
resourceType: base.ResTypeCommon,
entryType: base.Inbound,
batchCount: 1,
flag: 0,
slotChain: sc,
})
assert.Nil(t, b, "the entry should not be blocked")
assert.Equal(t, "abc", entry.Resource().Name())
entry.Exit()
ps1.AssertNumberOfCalls(t, "Prepare", 1)
rcs1.AssertNumberOfCalls(t, "Check", 1)
rcs2.AssertNumberOfCalls(t, "Check", 1)
ssm.AssertNumberOfCalls(t, "OnEntryPassed", 1)
ssm.AssertNumberOfCalls(t, "OnEntryBlocked", 0)
ssm.AssertNumberOfCalls(t, "OnCompleted", 1)
}
suite使用
package discovery
import (
"context"
"fmt"
"sync"
"testing"
"time"
"github.com/stretchr/testify/suite"
"go.etcd.io/etcd/integration"
"github.com/kubeservice-stack/common/pkg/config"
)
type ETCDMockCluster struct {
cluster *integration.ClusterV3
Endpoints []string
}
func StartEtcdMockCluster(t *testing.T) *ETCDMockCluster {
cluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
return &ETCDMockCluster{
cluster: cluster,
Endpoints: []string{cluster.Members[0].GRPCAddr()},
}
}
func (etcd *ETCDMockCluster) Terminate(t *testing.T) {
etcd.cluster.Terminate(t)
}
type EtcdClusterTestSuite struct {
suite.Suite
Cluster *ETCDMockCluster
}
func (s *EtcdClusterTestSuite) SetupTest() {
s.Cluster = StartEtcdMockCluster(s.T())
}
func (s *EtcdClusterTestSuite) TearDownTest() {
s.Cluster.Terminate(s.T())
}
func (s *EtcdClusterTestSuite) TestWriteRead() {
ed, err := newEtedDiscovery(config.Discovery{
Endpoints: s.Cluster.Endpoints,
}, "nobody")
s.Nil(err)
err = ed.Put(context.TODO(), "/test/key1", []byte("dongjiang"))
s.Nil(err)
d1, err1 := ed.Get(context.TODO(), "/test/key1")
s.Nil(err1)
s.Equal(string(d1), "dongjiang")
err2 := ed.Delete(context.TODO(), "/test/key1")
s.Nil(err2)
err3 := ed.Close()
s.Nil(err3)
}
// go test 入口
func TestEtcdClusterTestSuite(t *testing.T) {
suite.Run(t, new(EtcdClusterTestSuite))
}
高级使用
httpmock: local http server
package healthz
import (
"net/http"
"net/http/httptest"
"testing"
"code.iflytek.com/stc_sae/golang-template-project/pkg/routers"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func TestHealthzRoute(t *testing.T) {
assert := assert.New(t)
r := gin.Default()
router.Router(r)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/healthz", nil)
req.Host = "127.0.0.1:9445"
r.ServeHTTP(w, req)
assert.Equal(200, w.Code)
assert.Len(w.Body.String(), 15)
}
orm mock: 使用内存sqlite3
package models
import (
"testing"
"git.iflytek.com/stc_sae/sae-apiserver/pkg/common/orm"
"git.iflytek.com/stc_sae/sae-apiserver/pkg/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type ClusterSuite struct {
suite.Suite
g *orm.DBConn
}
func (suite *ClusterSuite) SetupTest() {
GlobalCfg = config.Orm{
DBType: config.SQLITE3,
Database: "file::memory:?cache=shared",
}
suite.g = Ormer()
}
func (suite *ClusterSuite) TearDownTest() {
assert := assert.New(suite.T())
err := suite.g.Where("1 = 1").Delete(&Cluster{}).Error
assert.NoError(err)
}
func (suite *ClusterSuite) TestCreateCluster() {
assert := assert.New(suite.T())
cm := &clusterModel{}
id, err := cm.Add(&Cluster{
Name: "aa",
})
assert.Equal(uint(1), id)
assert.NoError(err)
v, err := cm.GetById(uint(1))
assert.Equal("aa", v.Name)
assert.Equal("", v.DisplayName)
assert.NoError(err)
err = cm.UpdateByName(
&Cluster{
Name: "aa",
DisplayName: "this is test",
})
assert.NoError(err)
v, err = cm.GetById(uint(1))
assert.NoError(err)
assert.Equal("aa", v.Name)
assert.Equal("this is test", v.DisplayName)
err = cm.DeleteByName("abc", false)
assert.Error(err)
v, err = cm.GetByName("aa")
assert.NoError(err)
assert.Equal("aa", v.Name)
assert.Equal("this is test", v.DisplayName)
assert.NotNil(v.DeletedAt)
v, err = cm.GetById(uint(1))
assert.NoError(err)
assert.Equal("aa", v.Name)
assert.Equal("this is test", v.DisplayName)
assert.NotNil(v.DeletedAt)
err = cm.DeleteByName("aa", false)
assert.NoError(err)
v, err = cm.GetById(uint(1))
assert.Error(err)
}
func (suite *ClusterSuite) TestGetAllNormal() {
assert := assert.New(suite.T())
cm := &clusterModel{}
id, err := cm.Add(&Cluster{
Name: "a",
})
assert.NoError(err)
assert.Greater(id, uint(0))
id, err = cm.Add(&Cluster{
Name: "b",
})
assert.Greater(id, uint(1))
assert.NoError(err)
id, err = cm.Add(&Cluster{
Name: "c",
})
assert.Greater(id, uint(2))
assert.NoError(err)
vs, err := cm.GetNames()
assert.NoError(err)
assert.Len(vs, 3)
}
func TestClusterSuite(t *testing.T) {
suite.Run(t, new(ClusterSuite))
}
其他
「如果这篇文章对你有用,请随意打赏」
如果这篇文章对你有用,请随意打赏
使用微信扫描二维码完成支付