golang基础-单元测试与mock

golang 单元测试

单元测试介绍

为了保证代码的质量,不少公司都会要求写单元测试。这里介绍两个指标,git

  1. 函数覆盖率:函数调用个数/函数个数,一般要求100%
  2. 行覆盖率:走到的行的个数/总函数,一般要求>60%

经过单元测试,咱们能够针对不一样场景进行测试,是研发本身对质量的把控。 笔者目前所在的公司对单元测试要求很高,而且有替代测试的趋势。github

go test

  • go的test通常以xxx_test.go为文件名,xxx并无特别要求是要实测的文件名
  • TestMain做为初始化test
  • Testxxx(t* testing.T)
  • go test 便可运行单元测试
  • go test --v --test.run funcName 能够指定单测某个方法

建立一个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
复制代码

go convey

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)
复制代码

mock

什么是mock

单元测试的时候,若是流程中有第三方依赖怎么办?好比当贷款支付的时候,须要用户的额度,而额度信息存在于另外一个微服务,须要rpc拉取。为了解决这种场景,咱们可使用mock这种方式。简单来讲,mock就是能指定依赖接口的输入 输出,能够理解为提早插入的固定数据,如此,流程就能正常跑起来。测试

使用mockery进行mock

限制:ui

  • 只能针对接口进行mock

使用流程spa

  • 安装mockery:go get github.com/vektra/mockery/.../
  • mockery -name=接口名,生成mocks目录。

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)
    }
}
复制代码
相关文章
相关标签/搜索