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

Android/Kotlin:如何检测作为参数传递的函数是否被调用

检测作为参数传递的函数是否被调用的解决方案

当然有办法解决这个问题啦!在Kotlin中测试这类作为高阶函数参数传入的lambda是否被执行,最便捷的方式是借助Mocking库(比如MockK,对Kotlin的函数类型支持特别到位),如果不想引入第三方库,也可以手动实现简单的调用追踪逻辑。下面针对你的场景给出具体方案:

方案一:使用MockK(推荐)

MockK是专门为Kotlin设计的Mock库,能轻松追踪lambda的调用情况。

步骤1:添加MockK依赖

在你的项目构建文件(比如build.gradle.kts或build.gradle)中加入依赖:

// 针对JUnit 5
testImplementation("io.mockk:mockk:1.13.8")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2")

步骤2:编写测试用例

针对你的updateWeight函数,我们可以为每个传入的lambda创建mock,然后在调用目标方法后,验证对应的mock是否被调用:

import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Test
import android.text.Editable
import android.text.SpannableStringBuilder

class WeightUpdateTest {

    @Test
    fun `当输入为空时,应调用showEmptyError`() {
        // 1. 创建各个lambda的mock
        val showEmptyErrorMock = mockk<() -> Unit>(relaxed = true)
        val showOutOfRangeErrorMock = mockk<() -> Unit>(relaxed = true)
        val dismissAlertDialogMock = mockk<() -> Unit>(relaxed = true)
        val updateAndShowMock = mockk<(Float) -> Unit>(relaxed = true)
        
        // 2. 创建空输入的Editable对象
        val emptyInput = SpannableStringBuilder("   ") // 带空格的空字符串,trim后为空

        // 3. 调用目标方法
        updateWeight(emptyInput, showEmptyErrorMock, showOutOfRangeErrorMock, dismissAlertDialogMock, updateAndShowMock)

        // 4. 验证只有showEmptyError被调用
        verify(exactly = 1) { showEmptyErrorMock() }
        verify(exactly = 0) { showOutOfRangeErrorMock() }
        verify(exactly = 0) { dismissAlertDialogMock() }
        verify(exactly = 0) { updateAndShowMock(any()) }
    }

    @Test
    fun `当输入超过300时,应调用showOutOfRangeError`() {
        val showEmptyErrorMock = mockk<() -> Unit>(relaxed = true)
        val showOutOfRangeErrorMock = mockk<() -> Unit>(relaxed = true)
        val dismissAlertDialogMock = mockk<() -> Unit>(relaxed = true)
        val updateAndShowMock = mockk<(Float) -> Unit>(relaxed = true)
        
        val overRangeInput = SpannableStringBuilder("350")

        updateWeight(overRangeInput, showEmptyErrorMock, showOutOfRangeErrorMock, dismissAlertDialogMock, updateAndShowMock)

        verify(exactly = 0) { showEmptyErrorMock() }
        verify(exactly = 1) { showOutOfRangeErrorMock() }
        verify(exactly = 0) { dismissAlertDialogMock() }
        verify(exactly = 0) { updateAndShowMock(any()) }
    }

    @Test
    fun `当输入在正常范围时,应调用dismissAlertDialog和updateAndShow`() {
        val showEmptyErrorMock = mockk<() -> Unit>(relaxed = true)
        val showOutOfRangeErrorMock = mockk<() -> Unit>(relaxed = true)
        val dismissAlertDialogMock = mockk<() -> Unit>(relaxed = true)
        val updateAndShowMock = mockk<(Float) -> Unit>(relaxed = true)
        
        val validInput = SpannableStringBuilder("75.5")
        val expectedValue = 75.5f

        updateWeight(validInput, showEmptyErrorMock, showOutOfRangeErrorMock, dismissAlertDialogMock, updateAndShowMock)

        verify(exactly = 0) { showEmptyErrorMock() }
        verify(exactly = 0) { showOutOfRangeErrorMock() }
        verify(exactly = 1) { dismissAlertDialogMock() }
        verify(exactly = 1) { updateAndShowMock(expectedValue) }
    }
}

这里的relaxed = true表示mock会自动返回默认值(对于无返回值的lambda来说就是什么都不做),避免我们手动设置每个mock的行为。

方案二:手动实现调用追踪(无需第三方库)

如果不想引入MockK,你可以自己创建简单的类来记录函数是否被调用:

// 定义一个追踪类,用于记录函数调用状态
class CallTracker {
    var isCalled = false
        private set

    fun markCalled() {
        isCalled = true
    }
}

// 针对带参数的函数,可以扩展一个带参数记录的版本
class ParamCallTracker<T> {
    var lastCalledParam: T? = null
        private set
    var isCalled = false
        private set

    fun markCalled(param: T) {
        isCalled = true
        lastCalledParam = param
    }
}

然后编写测试用例:

import org.junit.jupiter.api.Test
import android.text.Editable
import android.text.SpannableStringBuilder
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class WeightUpdateManualTest {

    @Test
    fun `空输入时触发showEmptyError`() {
        val emptyErrorTracker = CallTracker()
        val outOfRangeTracker = CallTracker()
        val dismissTracker = CallTracker()
        val updateTracker = ParamCallTracker<Float>()

        val emptyInput = SpannableStringBuilder("")

        updateWeight(
            value = emptyInput,
            showEmptyError = { emptyErrorTracker.markCalled() },
            showOutOfRangeError = { outOfRangeTracker.markCalled() },
            dismissAlertDialog = { dismissTracker.markCalled() },
            updateAndShow = { updateTracker.markCalled(it) }
        )

        assertTrue(emptyErrorTracker.isCalled)
        assertFalse(outOfRangeTracker.isCalled)
        assertFalse(dismissTracker.isCalled)
        assertFalse(updateTracker.isCalled)
    }

    @Test
    fun `正常输入时触发dismiss和updateAndShow`() {
        val emptyErrorTracker = CallTracker()
        val outOfRangeTracker = CallTracker()
        val dismissTracker = CallTracker()
        val updateTracker = ParamCallTracker<Float>()

        val validInput = SpannableStringBuilder("80")
        val expectedValue = 80f

        updateWeight(
            value = validInput,
            showEmptyError = { emptyErrorTracker.markCalled() },
            showOutOfRangeError = { outOfRangeTracker.markCalled() },
            dismissAlertDialog = { dismissTracker.markCalled() },
            updateAndShow = { updateTracker.markCalled(it) }
        )

        assertFalse(emptyErrorTracker.isCalled)
        assertFalse(outOfRangeTracker.isCalled)
        assertTrue(dismissTracker.isCalled)
        assertTrue(updateTracker.isCalled)
        assertEquals(expectedValue, updateTracker.lastCalledParam)
    }
}

这两种方案都能帮你精准验证不同输入场景下,哪个传入的函数会被执行。根据项目需求选择即可,MockK更适合复杂场景,手动追踪则更轻量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:41:47