使用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
相关产品推荐
相关产品推荐

