Mockito Kotlin:如何验证作为另一个类构造参数的类的方法调用?
问题分析与解决方案
你的核心问题是测试中ClassA依赖的ClassB实例,和你用来验证的ClassB Mock实例不是同一个:
- 原测试类通过构造函数注入
ClassA时,Spring容器可能已经用ClassB的实际实例完成了ClassA的初始化; - 之后通过
@MockBean注册的ClassBMock实例,并没有替换掉ClassA内部持有的那个实际实例,所以验证时自然找不到调用记录。
可行的解决方案
方案1:让Spring用Mock实例自动注入ClassA(集成测试场景)
用@SpringBootTest启动测试上下文,通过@MockBean替换容器中的ClassB实例,再自动注入ClassA——此时ClassA内部的ClassB就是Mock实例,和你测试代码中持有的是同一个:
@SpringBootTest class Test { @Autowired private lateinit var classA: ClassA @MockBean private lateinit var classB: ClassB @Test fun testSomething() { classA.someMethod() verify(classB, times(1)).anotherMethod(arg1, arg2) } }
方案2:手动构造ClassA并传入Mock实例(单元测试场景)
如果不需要完整的Spring上下文,直接手动创建ClassB的Mock实例,再传给ClassA的构造函数,避免容器注入的混乱:
class Test { private val classBMock: ClassB = mock() private val classA: ClassA = ClassA(classBMock) @Test fun testSomething() { classA.someMethod() verify(classBMock, times(1)).anotherMethod(arg1, arg2) } }
关于“验证实际实例方法调用”的补充
如果确实需要验证ClassB实际实例的调用,只能把实际实例包装成Spy(Mockito的监控对象),但这种方式不推荐,因为会破坏封装且可能引入副作用:
- 先获取
ClassB的实际实例; - 把它包装成
Spy; - 替换
ClassA内部的ClassB实例(需要ClassA的classB字段是可修改的,或者用反射强行替换); - 最后对
Spy实例进行验证。
示例代码(需注意反射的局限性):
@SpringBootTest class Test { @Autowired private lateinit var classA: ClassA @Autowired private lateinit var realClassB: ClassB private lateinit var spyClassB: ClassB @BeforeEach fun setUp() { spyClassB = spy(realClassB) // 假设ClassA的classB是var类型,直接替换 classA.classB = spyClassB // 如果是val类型,需要用反射: // val field = ClassA::class.java.getDeclaredField("classB") // field.isAccessible = true // field.set(classA, spyClassB) } @Test fun testSomething() { classA.someMethod() verify(spyClassB, times(1)).anotherMethod(arg1, arg2) } }
内容的提问来源于stack exchange,提问作者Jurij Plaskan
相关产品推荐
相关产品推荐

