如何在Gomock中匹配含动态值的[]interface{}及bson.D参数
处理Gomock中带动态参数的方法Mock问题
一、Mock含动态字段的InsertManyDocument方法
实际调用时传入的data里有自动生成的动态值(比如time.Now()生成的时间戳),固定值匹配肯定失效,这时候得自定义参数匹配器,只校验我们关心的固定字段,忽略动态字段。
实现方式
- 先实现
gomock.Matcher接口,自定义匹配逻辑
假设你要插入的结构体是User,示例如下:type User struct { Name string CreateTime time.Time // 动态生成的字段 } // 自定义匹配器,只校验Name字段 type userMatcher struct { expectedName string } func (m userMatcher) Matches(x interface{}) bool { user, ok := x.(User) if !ok { return false } // 只对比固定字段,动态的CreateTime直接忽略 return user.Name == m.expectedName } func (m userMatcher) String() string { return fmt.Sprintf("匹配Name为%s的User", m.expectedName) } - 对
[]interface{}类型的data做匹配
如果切片元素顺序固定,直接用自定义匹配器构造预期切片:
如果元素顺序不固定,用oid1, _ := primitive.ObjectIDFromHex("60d21b4667d0d8992e610c85") oid2, _ := primitive.ObjectIDFromHex("60d21b4667d0d8992e610c86") expectedData := []interface{}{ userMatcher{expectedName: "Alice"}, userMatcher{expectedName: "Bob"}, } // 录制Mock调用 mockClient.EXPECT().InsertManyDocument(gomock.Eq(expectedData)). Return([]primitive.ObjectID{oid1, oid2}, nil)gomock.InAnyOrder()包裹预期切片:mockClient.EXPECT().InsertManyDocument(gomock.InAnyOrder(expectedData)). Return([]primitive.ObjectID{oid1, oid2}, nil)
二、处理UpdateOneDocumentWithBSON的动态参数校验
bson.D、options.ArrayFilters这类参数里有动态值时,没法直接用gomock.Any()(因为Mock方法要求传入具体类型,不是Matcher),同样用自定义校验逻辑解决,两种方式可选:
方式1:用gomock.MatchedBy()快速包装校验函数
直接写匿名函数或者单独函数来校验参数的关键字段,比如针对filter和update:
// 校验filter是否包含预期的_id matchFilter := func(filter primitive.D) bool { expectedID, _ := primitive.ObjectIDFromHex("60d21b4667d0d8992e610c85") for _, elem := range filter { if elem.Key == "_id" { id, ok := elem.Value.(primitive.ObjectID) return ok && id == expectedID } } return false } // 校验update的$set是否设置了正确的status matchUpdate := func(update bson.D) bool { for _, elem := range update { if elem.Key == "$set" { setData, ok := elem.Value.(bson.M) if ok && setData["status"] == "active" { return true } } } return false } // 录制Mock调用,用MatchedBy包装校验函数 mockClient.EXPECT().UpdateOneDocumentWithBSON( gomock.MatchedBy(matchFilter), gomock.Any(), // arrayFilter如果不关心就直接用Any() gomock.MatchedBy(matchUpdate), )
方式2:自定义Matcher处理复杂校验
如果校验逻辑比较复杂,就单独实现gomock.Matcher接口:
// 针对filter的自定义匹配器 type filterMatcher struct { expectedID primitive.ObjectID } func (m filterMatcher) Matches(x interface{}) bool { filter, ok := x.(primitive.D) if !ok { return false } for _, elem := range filter { if elem.Key == "_id" { id, ok := elem.Value.(primitive.ObjectID) return ok && id == m.expectedID } } return false } func (m filterMatcher) String() string { return fmt.Sprintf("匹配_id为%s的filter", m.expectedID.Hex()) } // 录制时直接传入自定义Matcher实例 expectedID, _ := primitive.ObjectIDFromHex("60d21b4667d0d8992e610c85") mockClient.EXPECT().UpdateOneDocumentWithBSON( filterMatcher{expectedID: expectedID}, gomock.Any(), // 这里可以再定义一个updateMatcher,逻辑和上面类似 gomock.Any(), )
内容的提问来源于stack exchange,提问作者bab165
相关产品推荐
相关产品推荐

