golang单测集成简化工具mockit【开源库】
2021-12-17 本文已影响0人
太白菜Rennbon
Mockit点击传送
目标:将mock变得简单,让代码维护变得容易
分支介绍
- main 主分支,覆盖了单元测试
- light 轻分支,去除了单元测试,简化了依赖项,方便其他团队使用
常见Mock难点
- 不同中间件,mock库设计模式不一致,学习代价高,差异化明显
- mock方案强依赖服务端,无法灵活解耦
- 单元测试适配各种中间件的方案后,依赖管理杂乱
- 综上所述不想写mock,也没有良好的可执行方案,放弃单测
mockit做到了什么
- 统一简化语法
- 无需服务端
- 解耦依赖项
- testMain统一管理
mockit 使用
目前支持
-
Redis
,MySQL
,Interface
,HTTP
-
GRPC
可以使用proto生成interface使用Interface
模拟 -
ElasticSearch
- 使用
HTTP
方式代理client,不过es的返回值比较复杂,请求路径没有普通HTTP直观 - 使用
Interface
方式,将dao
层抽象成接口方式,这种方式下,接口返回值模拟相对方便直观
- 使用
理论上业务抽象使用
Interface
方式都可达成
单元测试案例
func TestMain(m *testing.M) {
var err error
// interface intercept agent
// 初始化kit,一个new搞定
kit, err = New(mockinterface.NewMockDemoInterface)
if err != nil {
panic(err)
}
{ // 初始化mock service
// http.client需要InterceptHttpClient一下
cli := http.DefaultClient
kit.InterceptHttpClient(cli)
// 初始化的mock interface实例获取后需要反射一下
iImpl := kit.GetInterfaceClient("MockDemoInterface")
iface := iImpl.(*mockinterface.MockDemoInterface)
httpCli := mockhttp.NewMockHttpCli()
kit.InterceptHttpClient(httpCli.Client())
// 拦截
srv = &mockSrv{
es: mockes.NewMockEs(cli),
httpCli: httpCli,
iface: iface,
redis: mockredis.NewMockRedis(kit.RedisAddr()), // redis只要使用mockit返回的server地址
sql: mocksql.NewSqlDao(kit.Gorm2DB()), // mysql只需要替换gormDB
}
}
os.Exit(m.Run())
}
func TestDemo(t *testing.T){
// http mock
p := mockit.NewExpectParam().WithMethod("GET").
WithPath("http://sh-gateway.shihuo.cn/v4/services/sh-goodsinnerapi/style/get").
WithReturns(mockResp)
kit.HttpExpect(p, t)
// interface
p := mockit.NewExpectParam().
WithPath(labelLib).
WithMethod("BatchSalesSoarTagByStyleIds").
WithReturns([]*cbo.BatchGoodsSalesSoarTagModel{
{
StyleId: int64(collects[0].StyleId),
TagId: -1,
Value: 10000,
},
}, nil)
kit.InterfaceExpect(p, t)
// MySQL
p := mockit.NewExpectParam().
WithMethod("SELECT (.+) FROM `trd_user_collect_goods` WHERE user_id = (.+)$").
WithArgs(param.UserId, false).WithReturns(collects)
kit.MysqlQueryExpect(p, t)
}
准备 (具体参照kit_test.go)
- interface生成 https://github.com/golang/mock
// interface生成方式
$ mockgen -source ./iface/interface.go -package mockimpl -destination ./mockimpl/interface.go
// 而后将以下new方法的返回值改成interface{}
before: func NewMockDemoInterface(ctrl *gomock.Controller) *MockDemoInterface {
after: func NewMockDemoInterface(ctrl *gomock.Controller) interface{}} {
mock := &MockDemoInterface{ctrl: ctrl}
mock.recorder = &MockDemoInterfaceMockRecorder{mock}
return mock
}
- sqlmock依赖replace
目前需要替换下sqlmock库,目前pr还在合并中,预计最近2周就能OK
replace github.com/DATA-DOG/go-sqlmock v1.5.0 => github.com/Rennbon/go-sqlmock v1.5.1-0.20211212104631-9c4a20760689
mockit自身单测
- 当前目录下
iface
中有4个方法,mockimpl
中分别为各个mock实例的实现 - kit_test.go中
mockSrv
引用了这些mockimpl
实例,在testMain
中列举了mock的启动方式,并且在之后所有的Test中介绍了如何使用