【质量文化第二弹】单测系列-mockey框架:解决Mac系统下Mock测试

416 阅读3分钟

(由部门研发同学投稿)

在macbook开发机本地IDE执行 某模块单元测试的过程中,由于一些通用mock框架在macbook 11/12版本无法执行,导致部分逻辑难以覆盖。

在使用了 "github.com/bytedance/mockey" 后,解决了 mock 框架无法适配 mac 系统的问题,此模块 单元测试整体覆盖率已达到90%。

image.png

本文旨在分享 mockey 框架的使用方法,并与业内使用广泛的 gomonkey 框架进行对比。

业务代码,从redis中查询xxx缓存并解析成标准格式的业务代码逻辑,如下:

// XxxCache 缓存结构
    type XxxCache struct {
    	Advertiser string
    	TaTagId    []int64
    }
    
    // GetxxxCache 获取 rta 缓存
    func GetXxxCache(oneId string) []*RtaCache {
    	var xxxCaches []*XxxCache
    	cache, err := RedisQuery(id)
    	if err != nil {
    		return xxxCaches
    	}
    	/*
    		若干业务逻辑
    	*/
    	}
    	return xxxCaches
    }
    
    // RedisQuery 查询 redis
    func RedisQuery(id string) (map[string]string, error) {
    	var data map[string]string
    	/*
    		若干业务逻辑
    	*/
    	return data, nil
    }

现分别给出使用mockey和gomonkey两种框架的单元测试方法:

mockey + mockey 封装的PatchConvey
 func TestGetXxxCache_Mockey(t *testing.T) {
    	PatchConvey("TestGetXxxCache", t, func() {
    		PatchConvey("query redis err", func() {
    			Mock(RedisQuery).Return(nil, errors.New("mock redis query err")).Build()
    			data, err := GetXxxCache("1111")
    			So(err, ShouldNotBeNil)
    			So(err.Error(), ShouldEqual, "mock redis query err")
    			So(data, ShouldBeNil)
    		})
    		PatchConvey("query redis success", func() {
    			Mock(RedisQuery).Return(map[string]string{
    				"ad1": "1,2,3,4",
    				"ad2":  "1,a,b",
    			}, nil).Build()
    			data, err := GetXxxCache("1111")
    			So(err, ShouldBeNil)
    			So(data, ShouldNotBeNil)
    			So(len(data), ShouldEqual, 2)
    			...
    		})
    	})
    }

gomonkey + convey
func TestGetXxxCache_GoMonkey(t *testing.T) {
    Convey("TestGetXxxCache", t, func() {
        Convey("RedisQuery err", func() {
            patches := gomonkey.ApplyFunc(RedisQuery, func(id string) (map[string]string, error) {
                return nil, errors.New("mocked RedisQuery error")
            })
            defer patches.Reset()
            xxxCaches, err := GetXxxCache("1111")
            So(err, ShouldNotBeNil)
            So(err.Error(),ShouldEqual,"mocked RedisQuery error")
        })
        Convey("query redis success", func() {
            patches := gomonkey.ApplyFunc(RedisQuery, func(id string) (map[string]string, error) {
                return map[string]string{"ad1": "1,2,3,4", "ad2": "1,a,b"}, nil
            })
            defer patches.Reset()
            data, err := GetXxxCache("1111")
            So(err, ShouldBeNil)
            So(data, ShouldNotBeNil)
        })
    })
}

对比

总得来说,推荐使用mockey框架进行 mock。无论是从 mock 代码的编写,mock 代码的可读性,使用的便捷性,mockey 都要优于 gomonkey。

bytedance/mockeyagiledragon/gomonkey
mac 本地可执行需要获取较高系统权限,在比如macos 10.5+无法执行
无需Reset,每个 mock 的生命周期为当前的PatchConvey需要显式 defer patch.Reset()
mock 简单,函数名 + Return + Buildmock 较繁琐,需要输入mock 对象对应的 func

更多信息请查看官方文档

mockey库:github.com/bytedance/m…

gomonkey库:github.com/agiledragon…

总结

以上是我在公司宣传的单测系列的第二期内容,它是对第一期的延续。你还记得我们第一期内容最后同事提出的问题吗?由于我们公司的开发主要使用 Macbook 11/12 芯片,使用 GoMonkey 的项目在本地的 Mac 上无法正常运行。这个问题导致了需要进行模拟的代码无法编写单元测试覆盖。

为了解决这个问题,团队成员进行了调研和比较,最终决定采用 Mockey 库。由负责该模块的同学推动,该模块的单元测试覆盖率已经达到了90%的高水平👏👏。这位同学将整个过程进行了总结,并投稿给了质量文化宣传团队,希望与大家分享这次的经验。


后续的每一期内容我都会及时发布在掘金的工程师质量文化专栏,欢迎大家关注,共同进步。

最后,照例给大家看下我们在公司张贴的海报吧~

工位.JPG