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

所有公共方法都使用私有变量的类如何编写可正常运行的单元测试?

问题根因

你当前的测试存在三个核心错误:

  • 你直接将被测类LoginInteractor声明为@Mock对象,Mock对象的所有方法默认返回对应类型的默认值:布尔类型返回false,对象类型返回null,这是两个测试用例失败的直接原因,你完全没有调用LoginInteractor的真实逻辑。
  • 初始化顺序错误:即使你不用Mock的LoginInteractor,如果先初始化LoginInteractor再替换LoginSessionManager的单例,LoginInteractor构造时已经拿到了旧的LoginSessionManager实例,依赖替换不会生效。
  • 方法调用写法错误:Java类的非@JvmField成员方法在Kotlin中需要显式调用方法,你写的loginSessionManager.isLoggedIn是属性访问写法,不会匹配到Java的isLoggedIn()方法,导致Mock规则不生效。
修复方案

调整测试逻辑,只Mock被测类的依赖,调整初始化顺序保证依赖替换生效,修正方法调用写法即可,修复后代码如下:

@RunWith(PowerMockRunner::class)
@PrepareForTest(
    TextUtils::class,
    LoginInteractor::class,
    LoginSessionManager::class
)
class LoginInteractorTest : TestCase() {
    // 只Mock被测类的依赖LoginSessionManager
    @Mock
    private lateinit var loginSessionManager: LoginSessionManager
    
    // 声明真实的被测类实例
    private lateinit var loginInteractor: LoginInteractor

    @Throws(Exception::class)
    public override fun setUp() {
        MockitoAnnotations.openMocks(this)
        // 第一步:先替换LoginSessionManager的全局单例
        Whitebox.setInternalState(LoginSessionManager::class.java, "loginSessionManager", loginSessionManager)
        // 第二步:清空LoginInteractor旧的单例,让它重新初始化,此时构造函数会拿到我们替换后的mock实例
        Whitebox.setInternalState(LoginInteractor::class.java, "instance", null as LoginInteractor?)
        // 获取真实的被测类实例
        loginInteractor = LoginInteractor.getInstance()

        // 也可以跳过上面两步,直接强制替换LoginInteractor内部的依赖,效果一致:
        // loginInteractor = Whitebox.invokeConstructor(LoginInteractor::class.java)
        // Whitebox.setInternalState(loginInteractor, "loginSessionManager", loginSessionManager)
    }

    @Test
    fun isLoggedInTest(){
        // 修正为方法调用写法
        `when`(loginSessionManager.isLoggedIn()).thenReturn(true)
        assertEquals(true, loginInteractor.isLoggedIn())
    }

    @Test
    fun getLoginIntentTest(){
        val expectIntent = Intent()
        `when`(loginSessionManager.getLoginIntent()).thenReturn(expectIntent)
        assertEquals(expectIntent, loginInteractor.getLoginIntent())
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 01:36:00