Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc

1. 引言

本文是一篇对mock库的小结。

2. 怎么理解mock这件事

2.1 为什么需要mock

最常见的场景是,一个服务B和它依赖的上游微服务A同时启动开发。为了加快开发速度,服务B不可能等到服务A开发完,在启动开发。因此服务A和服务B约定它们之间交互的接口,然后就可以启动开发了。

服务B为了验证自身的业务逻辑,它需要mock一个A服务(只需要mock相关接口)。但是mock A服务本身可能也比较麻烦,涉及到网络IO,端口占用等等。所以进一步的,我们只需把与服务A的交互封装到一个interface中。这样只需要mock这个interface就可以了。

2.2 示例

mock最常见的场景是用于单元测试
完整示例
biz.go

type People interface {
    Say(s string) string
}

// 业务逻辑
func BizLogic(p People, s string) string {
    return "People Say:" + p.Say(s)
}

在单元测试中,验证我们的业务逻辑
biz_test.go

import (
    "github.com/stretchr/testify/mock"
    "testing"
)
type FakePeople struct {
    mock.Mock
}

func (m *FakePeople) Say(str string) string {
    args := m.Called(str)
    return args.String(0)
}

func TestSomething(t *testing.T) {

    // create an instance of our test object
    testObj := new(FakePeople)

    // setup expectations
    testObj.On("Say", "Jack").Return("hello Jack")
    testObj.On("Say", "Lucy").Return("hello Lucy")

    // call the code we are testing
    expected := "People Say:hello Jack"
    got := BizLogic(testObj, "Jack")
    if expected == got {
        t.Logf("got = %v; expected = %v", got, expected)
    } else {
        t.Errorf("got = %v; expected = %v", got, expected)
    }
}

2.3 实现原理

FakePeople是一个实现了接口People的类。有时候它也被称为Stub。它可以被理解为一个占位符,替代对真实的服务交互过程。

我们为针对它的请求预设了返回结果
每一组 请求+return 在stretchr/testify中被称为call

mock.go

type Call struct {
    Parent *Mock

    // The name of the method that was or will be called.
    Method string

    // Holds the arguments of the method.
    Arguments Arguments

    // Holds the arguments that should be returned when
    // this method is called.
    ReturnArguments Arguments
    ...

ExpectedCalls

methodName methodArguments ReturnArguments
"Say" ["Jack"] ["hello Jack"]
"Say" ["Lucy"] ["hello Lucy"]

当执行

p.Say(s)

会在预设的ExpectedCalls中进行查找,看是否有匹配的call,有就返回对应的ReturnArguments, 否则会抛出异常。

3. 三种常见的mock库

3.1 仓库

备注
golang/mock golang官方出品
stretchr/testify
agiledragon/gomonkey

3.2 支持范围

library interface function member method function variable
golang/mock
stretchr/testify
agiledragon/gomonkey

3.3 小结

其实从实现上讲golang/mockstretchr/testify属于同一类,都只支持interface
golang/mock相比stretchr/testify功能更强大,提供mockgen工具可以针对interface通过反射自动生成stub。对应 2.2情况,它可以自动生成实现接口People的类FakePeople

agiledragon/gomonkey是在编译阶段替换了符号表中符号对应的地址,因此它的支持范围更大。

后记

针对redis的单元测试可以使用
alicebob/miniredis


微信公众号

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注