You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:重构代码引入依赖注入(最推荐)

无需使用反射等黑科技,符合可测试性编码规范,后续维护成本最低:

  1. 修改my类的构造函数,将subClass实例作为可传入的参数,保留默认值兼容原有业务逻辑
    // 重构后的业务代码
    class my(val b: subClass = new subClass()) {
      def a () = "not mocked"
    
      class subClass {
        def ret () = "not mocked"
      }
    }
    
  2. 测试时直接构造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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 23:54:06