使用gomock可以模拟类型断言吗?无法实现时该采用什么方案?
问题解答
核心结论
Gomock无法直接伪造类型断言的返回结果。Go的类型断言基于变量的底层真实类型匹配,Gomock生成的*MockFoo和你定义的*A、*B是完全独立的类型,不可能通过类型断言匹配到*A或*B分支。
方案1:不修改现有业务代码的测试方式
如果暂时不想调整业务逻辑,可以直接绕开Gomock的mock实例做测试:
- 要测试
*A/*B分支时,直接初始化真实的*A/*B实例传入DoSomething即可,两个结构体本身就实现了foo接口,符合入参要求。如果A/B有外部依赖,给对应字段赋值测试桩数据即可。 - 要测试
default分支时,直接传入Gomock生成的*MockFoo实例即可,默认就会命中default分支。
方案2:推荐的可维护性重构方案
对接口做类型断言本身属于接口抽象泄露,违背了接口隐藏实现细节的设计原则,建议重构逻辑彻底解决问题:
方案2.1:把分支逻辑收敛到接口方法
给foo接口新增对应逻辑的方法,让不同实现类自己实现分支逻辑:
type foo interface { // 新增方法,对应原来每个分支的处理逻辑 Do() } func (a *A) Do() { // 原switch中*A分支的逻辑 } func (b *B) Do() { // 原switch中*B分支的逻辑 } func DoSomething(i foo) { // 直接调用接口方法,不需要类型断言 i.Do() }
重构后直接用Gomock mockfoo接口的Do方法,设置不同的预期返回即可覆盖所有逻辑,不需要关心类型匹配问题。
方案2.2:抽离类型分发逻辑为可替换变量
如果foo接口是第三方依赖无法修改,可以把类型判断的逻辑抽成可替换的公共变量:
// 抽离类型分发逻辑,测试时可替换 var dispatchType = func(i foo) { switch currentType := i.(type) { case *A: // 原*A分支逻辑 case *B: // 原*B分支逻辑 default: // 原default逻辑 } } func DoSomething(i foo) { dispatchType(i) }
测试时直接把dispatchType替换为自定义的桩函数,就可以模拟任意分支的执行,不需要关注入参的真实类型。
内容的提问来源于stack exchange,提问作者kito
相关产品推荐
相关产品推荐

