如何用Mockito模拟创建新对象的方法?测试场景疑难求解
解决temp类updateDetails()方法中无法模拟storage实例的问题
你遇到的核心问题是代码紧耦合:updateDetails()方法里直接实例化了storage()对象,导致测试时无法替换成模拟实例,Mockito自然没法拦截这种硬编码的对象创建,最终实际的storage实例因为context未初始化报错。下面给你几个可行的解决方案:
方案1:依赖注入(最推荐)
把storage作为依赖通过构造函数传入temp类,这样测试时就能轻松替换成模拟对象。
修改后的temp类:
class temp(private val storage: Storage) { fun updateDetails() { //do some work storage.set(storedata) } }
测试代码示例:
import org.junit.Test import org.mockito.Mockito.* class TempTest { @Test fun updateDetails_callsStorageSet() { // 模拟Storage实例 val mockStorage = mock(Storage::class.java) val tempInstance = temp(mockStorage) tempInstance.updateDetails() // 验证set方法是否被调用 verify(mockStorage).set(any()) } }
这种方式彻底解耦了temp和storage,符合依赖倒置原则,后续维护和测试都更方便。
方案2:用Mockito的mockConstruction API(适合无法修改构造函数的场景)
如果没法改动temp类的构造逻辑,Mockito 3.5及以上版本提供了mockConstruction API,可以拦截类的实例化过程,返回模拟对象。
测试代码示例:
import org.junit.Test import org.mockito.Mockito.* import org.mockito.junit.MockitoJUnitRunner import org.junit.runner.RunWith @RunWith(MockitoJUnitRunner::class) class TempTest { @Test fun updateDetails_callsStorageSet() { // 拦截Storage的实例化,返回模拟对象 mockConstruction(Storage::class.java) { mock, context -> // 这里可以对mock做初始化,比如设置所需的context `when`(mock.context).thenReturn(mockContext) }.use { val tempInstance = temp() tempInstance.updateDetails() // 验证模拟的Storage的set方法被调用 val mockStorage = it.constructed().first() verify(mockStorage).set(any()) } } }
这个方法不需要修改原有业务代码,但依赖Mockito的新版本,而且如果storage有复杂的初始化逻辑,可能需要在lambda里额外处理。
方案3:提取工厂方法(最小改动现有代码)
在temp类里提取一个创建storage的工厂方法,测试时通过子类重写这个方法返回模拟对象。
修改后的temp类:
open class temp { fun updateDetails() { //do some work createStorage().set(storedata) } // 提取工厂方法,protected/open方便测试时重写 protected open fun createStorage(): Storage { return storage() } }
测试代码示例:
import org.junit.Test import org.mockito.Mockito.* class TempTest { @Test fun updateDetails_callsStorageSet() { // 创建temp的子类,重写createStorage返回模拟对象 val mockStorage = mock(Storage::class.java) val tempInstance = object : temp() { override fun createStorage(): Storage { return mockStorage } } tempInstance.updateDetails() verify(mockStorage).set(any()) } }
这种方式对现有代码的改动最小,只需要新增一个工厂方法,适合不能大规模重构的场景。
内容的提问来源于stack exchange,提问作者coder




