为了保证代码的质量,不少公司都会要求写单元测试。这里介绍两个指标,git
经过单元测试,咱们能够针对不一样场景进行测试,是研发本身对质量的把控。 笔者目前所在的公司对单元测试要求很高,而且有替代测试的趋势。github
建立一个client包进行示例,包结构以下golang
.
├── client.go
├── client_test.go
复制代码
func TestUser(t *testing.T) {
var u = &User{Age: 15, Name: "alice"}
if u.Age != 15 {
t.Error("age err")
}
if u.Name != "bob" {
t.Error("name err")
}
}
复制代码
因为Name不符合预期,则会有以下提示bash
--- FAIL: TestUser (0.00s)
client_test.go:28: name err
FAIL
exit status 1
FAIL test/mocktest 0.005s
复制代码
goconvey能够很好的支持setup和teardown,goconvey能够在运行单个测试用例前都进行一次状态初始化和销毁。goconvey还有不少已经定义好了的可以直接使用的assert函数,而且能够自定义assert函数。 经常使用的assert以下:函数
var (
ShouldEqual = assertions.ShouldEqual
ShouldNotEqual = assertions.ShouldNotEqual
ShouldBeGreaterThan = assertions.ShouldBeGreaterThan
ShouldBeGreaterThanOrEqualTo = assertions.ShouldBeGreaterThanOrEqualTo
ShouldBeLessThan = assertions.ShouldBeLessThan
ShouldBeLessThanOrEqualTo = assertions.ShouldBeLessThanOrEqualTo
ShouldBeBetween = assertions.ShouldBeBetween
ShouldNotBeBetween = assertions.ShouldNotBeBetween
ShouldBeBetweenOrEqual = assertions.ShouldBeBetweenOrEqual
ShouldNotBeBetweenOrEqual = assertions.ShouldNotBeBetweenOrEqual
ShouldContainSubstring = assertions.ShouldContainSubstring
ShouldNotContainSubstring = assertions.ShouldNotContainSubstring
ShouldPanic = assertions.ShouldPanic
ShouldBeError = assertions.ShouldBeError
)
复制代码
使用举例:微服务
func TestUser(t *testing.T) {
convey.Convey("TestUser", t, func() {
var u = &User{Age: 15, Name: "alice"}
convey.So(u.Age, convey.ShouldEqual, 15)
convey.So(u.Name, convey.ShouldEqual, "bob")
})
}
复制代码
因为Name不符合预期,会出现以下提示单元测试
Line 30:
Expected: 'bob'
Actual: 'alice'
(Should be equal)
复制代码
单元测试的时候,若是流程中有第三方依赖怎么办?好比当贷款支付的时候,须要用户的额度,而额度信息存在于另外一个微服务,须要rpc拉取。为了解决这种场景,咱们可使用mock这种方式。简单来讲,mock就是能指定依赖接口的输入 输出,能够理解为提早插入的固定数据,如此,流程就能正常跑起来。测试
限制:ui
使用流程spa
rpc接口定义,接口实现
client.go:
package rpc
//go:generate mockery -name=Client
type Client interface {
Get(key string) (data interface{}, err error)
}
type ClientImpl struct {
Ct Client
}
func (p *ClientImpl) Get(key string) (data interface{}, err error) {
if mockCondition {
return p.Ct.Get(key)
}
// real logic
}
复制代码
client_test.go
package rpc
import (
"fmt"
"test/mocktest/mocks"
"testing"
)
type User struct {
Age int
Name string
}
func TestMock(t *testing.T) {
convey.Convey("TestMock", t, func() {
mc := &mocks.Client{}
var u = &User{Age: 15, Name: "alice"}
mc.On("Get", "alice").Return(u, nil)
ci.Ct = mc
data, err := ci.Get("alice")
convey.So(data.Age, convey.ShouldEqual, 15)
}
}
复制代码