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

Kotlin单元测试中如何Mock Handler(Looper)?代码测试咨询

在Kotlin单元测试中用Mockito处理Handler延迟执行代码

直接测试这段包含postDelayed的代码会遇到两个问题:单元测试环境默认没有主线程Looper,导致代码无法正常执行;2秒延迟会拖慢测试速度,还可能导致断言时机错误。用Mockito可以通过以下方式解决:

步骤1:改造原代码,抽离Handler依赖

为了能在测试中替换Handler,需要把Handler的创建逻辑抽成可覆盖的方法:

// 原业务类
class YourBusinessClass {
    lateinit var managerService: ManagerService
    var fwStatus: String = "--"
    private val versionValue = "Firmware: " // 假设这是类中已有的变量

    // 抽离Handler创建方法,测试时可覆盖
    open fun getMainHandler(): Handler = Handler(Looper.getMainLooper())

    // 触发延迟逻辑的方法(假设原代码是在这个方法里)
    fun startFirmwareCheck() {
        getMainHandler().postDelayed(
            {
                println("inside the looper")
                val firmwareVersion = managerService.getDeviceFirmwareVersion()
                fwStatus = if (!firmwareVersion.isNullOrEmpty()) "$versionValue $firmwareVersion" else "--"
                UpdateManagerInstance.disconnectFromUpdateService()
            }, 2000
        )
    }
}

步骤2:编写Mockito测试用例

通过mock Handler捕获延迟任务,直接执行跳过延迟,同时mock依赖的服务验证逻辑:

import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.*

@RunWith(MockitoJUnitRunner::class)
class YourBusinessClassTest {

    @Mock
    lateinit var mockHandler: Handler

    @Mock
    lateinit var mockManagerService: ManagerService

    @Captor
    lateinit var runnableCaptor: ArgumentCaptor<Runnable>

    private lateinit var businessClass: YourBusinessClass

    @Test
    fun `test firmware check logic after delayed task`() {
        // 初始化测试类,替换为mock的Handler
        businessClass = object : YourBusinessClass() {
            override fun getMainHandler(): Handler = mockHandler
        }
        businessClass.managerService = mockManagerService

        // 模拟managerService返回固件版本
        whenever(mockManagerService.getDeviceFirmwareVersion()).thenReturn("v2.1.0")

        // 触发延迟逻辑
        businessClass.startFirmwareCheck()

        // 验证Handler的postDelayed被调用,捕获传入的Runnable
        verify(mockHandler).postDelayed(runnableCaptor.capture(), eq(2000L))

        // 直接执行捕获到的Runnable,跳过2秒延迟
        runnableCaptor.value.run()

        // 断言固件状态是否正确设置
        assert(businessClass.fwStatus == "Firmware: v2.1.0")

        // 验证单例服务的断开方法被调用
        mockStatic(UpdateManagerInstance::class.java) {
            verify(UpdateManagerInstance).disconnectFromUpdateService()
        }
    }
}

关键说明

  • 抽离Handler:通过开放Handler的创建方法,让测试可以注入mock对象,避免依赖真实的主线程Looper。
  • 捕获Runnable:用ArgumentCaptor捕获延迟任务,直接执行就能同步完成逻辑验证,不需要等待真实延迟。
  • Mock依赖:对managerService和单例UpdateManagerInstance进行mock,确保测试只关注当前逻辑,不受外部依赖影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 23:55:11