Scala如何实现对嵌套类成员方法的mock操作?
my.b.ret() 调用Mock可行方案 前提说明
你提供的原始类定义如下:
class my { val b = new subClass() def a () = "not mocked" class subClass { def ret () = "not mocked" } }
由于b是my类内部硬编码实例化的固定值,且subClass是绑定到my实例的内部类,可根据是否能修改业务代码选择以下方案:
方案1:重构代码引入依赖注入(最推荐)
无需使用反射等黑科技,符合可测试性编码规范,后续维护成本最低:
- 修改
my类的构造函数,将subClass实例作为可传入的参数,保留默认值兼容原有业务逻辑// 重构后的业务代码 class my(val b: subClass = new subClass()) { def a () = "not mocked" class subClass { def ret () = "not mocked" } } - 测试时直接构造
subClass的mock实例传入my类即可,以Mockito Scala为例:import org.mockito.Mockito._ import org.scalatestplus.mockito.MockitoSugar val mockSub = mock[my#subClass] when(mockSub.ret()).thenReturn("mock返回值") val testMy = new my(mockSub) // 此时testMy.b.ret()会返回设定的mock值
方案2:Mock框架+反射替换字段(无需修改业务代码)
如果不能调整原有业务代码,可以通过反射修改my实例的私有val字段,搭配Mock框架实现需求,支持Mockito Scala、ScalaMock等常用Scala测试框架:
import org.mockito.Mockito._ import java.lang.reflect.Field val realMy = new my() // 构造绑定到当前realMy实例的内部类mock对象 val mockSub = mock[realMy.subClass] when(mockSub.ret()).thenReturn("mock返回值") // 反射修改b字段的值 val bField: Field = classOf[my].getDeclaredField("b") bField.setAccessible(true) bField.set(realMy, mockSub) // 此时调用realMy.b.ret()即可返回mock值
方案3:使用ScalaMock原生内部类Mock能力
ScalaMock原生支持绑定外部实例的内部类Mock,写法更简洁,无需处理内部类的绑定逻辑:
import org.scalamock.scalatest.MockFactory val realMy = new my() val mockSub = mock[realMy.subClass] // 设定mock方法返回值 (mockSub.ret _).expects().returning("mock返回值") // 同样用反射替换b字段即可 val bField = classOf[my].getDeclaredField("b") bField.setAccessible(true) bField.set(realMy, mockSub)
内容的提问来源于stack exchange,提问作者Tejas Patil
相关产品推荐
相关产品推荐

