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

如何使用Mockito模拟Scala Object中的嵌套方法?

Scala Object 模拟问题解决方案

首先明确:RETURNS_DEEP_STUBS 无法用于 Scala Object。它是为类实例的深层嵌套模拟设计的,而 Scala Object 在 JVM 层面是静态类+静态方法,没有可创建的实例对象,自然无法生成深层存根。

针对你的场景(Object 间嵌套调用导致 NPE),提供以下两种可行方案:

方案1:重构代码为可依赖注入的结构(推荐)

将原有的 Scala Object 拆分为 Trait + 单例实现,让方法依赖可替换的接口,这样就能用常规 Mockito 模拟行为。

原代码结构

package com.packageA
object ObjA {
  def method1(): String = ObjB.method2()
}

package com.packageB
object ObjB {
  def method2(): String = ObjC.method3()
}

package com.packageB
object ObjC {
  def method3(): String = "real_result"
}

重构后代码

// 定义Trait抽象行为
package com.packageA
trait ObjATrait {
  def method1(): String
}
// 原Object转为Trait的单例实现
object ObjA extends ObjATrait {
  // 若需要更灵活的依赖,可将ObjBTrait作为参数或隐式参数传入
  override def method1(): String = ObjB.method2()
}

package com.packageB
trait ObjBTrait {
  def method2(): String
}
object ObjB extends ObjBTrait {
  override def method2(): String = ObjC.method3()
}

package com.packageB
trait ObjCTrait {
  def method3(): String
}
object ObjC extends ObjCTrait {
  override def method3(): String = "real_result"
}

测试代码

测试时模拟对应的 Trait 实例,替换原有依赖:

import org.mockito.Mockito._
import org.scalatest.BeforeAndAfterEach
import org.scalatest.mockito.MockitoSugar
import org.scalatest.flatspec.AnyFlatSpec

class ObjATest extends AnyFlatSpec with MockitoSugar with BeforeAndAfterEach {
  it should "mock nested Object calls via traits" in {
    val mockObjB = mock[ObjBTrait]
    val mockObjC = mock[ObjCTrait]
    
    when(mockObjB.method2()).thenReturn("mocked_method2")
    when(mockObjC.method3()).thenReturn("mocked_method3")
    
    // 通过匿名实现注入模拟实例
    val testObjA = new ObjATrait {
      override def method1(): String = mockObjB.method2()
    }
    
    assert(testObjA.method1() == "mocked_method2")
  }
}

方案2:使用 PowerMock 模拟静态方法(适配现有代码)

如果不想重构代码,PowerMock 可以直接模拟 JVM 静态方法(Scala Object 的方法本质是静态方法),拦截嵌套调用避免 NPE。

测试代码示例

import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitSuite

@RunWith(classOf[PowerMockRunner])
@PrepareForTest(Array(classOf[com.packageB.ObjB], classOf[com.packageB.ObjC]))
class ObjATest extends JUnitSuite {
  test("mock Scala Object static methods") {
    // 模拟ObjB的method2
    PowerMockito.mockStatic(classOf[com.packageB.ObjB])
    PowerMockito.when(com.packageB.ObjB.method2()).thenReturn("mocked_method2")
    
    // 按需模拟ObjC的method3
    PowerMockito.mockStatic(classOf[com.packageB.ObjC])
    PowerMockito.when(com.packageB.ObjC.method3()).thenReturn("mocked_method3")
    
    val result = com.packageA.ObjA.method1()
    assert(result == "mocked_method2")
  }
}

注意事项

  • PowerMock 会修改类加载器,可能和部分测试框架或插件存在兼容性问题
  • 尽量只在无法重构的老代码中使用这种方式

内容的提问来源于stack exchange,提问作者kiruba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:25:24