版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | http://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

methodNamemethodArgumentsReturnArguments
“Say”[“Jack”][“hello Jack”]
“Say”[“Lucy”][“hello Lucy”]

当执行

p.Say(s)

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

3. 三种常见的mock库

3.1 仓库

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

3.2 支持范围

libraryinterfacefunctionmember methodfunction variable
golang/mock
stretchr/testify
agiledragon/gomonkey

3.3 小结

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

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

后记

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


微信公众号