如何使用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
相关产品推荐
相关产品推荐

