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

使用MockK模拟Kotlin带自定义get/set的var属性时报MockKException如何解决

错误原因

报错是因为setProperty的MockK语法不完整,你只指定了属性名,没有匹配赋值操作的参数规则,MockK无法识别对应的setter调用,所以抛出了缺失mock调用的异常。

解决方案1:修正动态遍历写法

给setProperty补充参数匹配规则value any(),同时适配getter的返回类型:

private val sharedPreferences = mutableMapOf<String, Any>()
// ...
val preferences = mockk<Preferences>()

listOf("coins", "pressure").forEach { key ->
    // getter 适配返回类型,Int属性默认值补0
    every { preferences getProperty key } answers {
        sharedPreferences[key] as? Int ?: 0
    }
    // setter 补充value匹配规则
    every { preferences setProperty key value any<Int>() } answers {
        sharedPreferences[key] = fieldValue
        fieldValue
    }
}

注意:如果你的Preferences类中有不同类型的属性(比如String、Boolean),需要按类型分组遍历,setter的any()要指定对应类型,避免匹配错误。

解决方案2:显式Mock单个属性(更推荐,可读性更高)

如果属性数量不多,直接写每个属性的mock规则,避免反射式写法的类型匹配问题:

private val sharedPreferences = mutableMapOf<String, Any>()
val preferences = mockk<Preferences>()

// 模拟coins属性
every { preferences.coins } answers { sharedPreferences["coins"] as? Int ?: 0 }
every { preferences.coins = any() } answers { sharedPreferences["coins"] = it.invocation.args[0] }

// 模拟pressure属性
every { preferences.pressure } answers { sharedPreferences["pressure"] as? Int ?: DEFAULT_PRESSURE }
every { preferences.pressure = any() } answers { sharedPreferences["pressure"] = it.invocation.args[0] }

更优实践:抽接口实现假数据

单元测试中可以不用MockK模拟,直接把Preferences抽象为接口,测试时写内存实现,性能更高也更稳定:

interface Preferences {
    var coins: Int
    var pressure: Int
}

// 生产环境实现
class SharedPrefsPreferences(private val context: Context) : Preferences {
    private val preferences: SharedPreferences =
        context.getSharedPreferences("name_of_file", Context.MODE_PRIVATE)
        
    override var coins: Int
        get() = preferences.getInt(KEY_COINS, 0)
        set(value) = preferences.edit { putInt(KEY_COINS, value) }
        
    override var pressure: Int
        get() = preferences.getInt(KEY_PRESSURE, DEFAULT_PRESSURE)
        set(value) = preferences.edit { putInt(KEY_PRESSURE, value) }
}

// 测试用内存实现
class TestPreferences : Preferences {
    override var coins: Int = 0
    override var pressure: Int = DEFAULT_PRESSURE
}

测试时直接注入TestPreferences实例即可,无需Mock框架介入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 14:06:06