【问题标题】:Junit not creating shared preference instance saying context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE) must not be nullJunit 没有创建共享首选项实例说 context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE) 不能为空
【发布时间】:2026-01-11 18:45:01
【问题描述】:

我正在为 sharedpreferences 编写一个 JUnit 测试用例,如下所示

class SharedPrefTest {

    private lateinit var context: Context
    private lateinit var userRepo: UserRepo
    private lateinit var sharedPreferences: SharedPreferences

    @Before
    fun setup() {
        context = mock()
        userRepo = UserRepo(context)
    }

    @Test
    fun `check mocked instances are not null`() {
        context assertNotEquals null //mocked successfully
        userRepo assertNotEquals null
    } //PASS

    @Test
    fun `when shared pref instance not null then do further ops`() {
        sharedPreferences = context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE)
        sharedPreferences assertNotEquals null
    } //FAIL

    companion object {
        const val USER_PREFS = "userprefs"
    }

}

但是,我遇到了错误。

context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE) must not be null
java.lang.NullPointerException: context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE) must not be null

我已经在单独的单元测试用例中检查了 context is not null 但仍然失败。

【问题讨论】:

  • 我不明白这个问题!您已经模拟了上下文。为什么它会向 getSharedPreferences 返回非存根(非空)响应?
  • 使用Robolectric 编写单元测试。您无需手动模拟 Context 等 Android 框架依赖项。
  • @ashu 问题在于它没有创建 sharedpreference 的实例并抛出 null 错误。此外,仅限使用 Mockito

标签: android kotlin junit mockito sharedpreferences


【解决方案1】:

问题在于它没有创建 sharedpreference 的实例并抛出 null 错误。

为什么一个模拟对象会调用它的具体实现?模拟对象是一个 stub,其行为已针对特定测试场景进行了预配置。在测试期间,客户端应该明确指定如果在模拟对象上调用特定方法会发生什么。如果客户端不提供这样的规范,模拟对象通常会默认为不返回 void 的方法返回零值; null 在 Mockito(更具体地说是 Java)的情况下。

您正在模拟 context,因此,context.getSharedPreferences() 返回默认的 null 值。由于 sharedPreferences 字段被声明为 Kotlin 不可为空的类型,因此将 null 分配给它会引发 NPE。您可以通过从 context.getSharedPreferences() 返回一个模拟的 SharedPreferences 实例来修复它。

@Test
fun `when shared pref instance not null then do further ops`() {
    val mockPrefs: SharedPreferences = mock()
    `when`(context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE))
        .thenReturn(mockPrefs);
    sharedPreferences = context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE)
    sharedPreferences assertNotEquals null
}

更好的方法是使用适用于 Android 的单元测试框架,例如 Robolectric

import androidx.test.core.app.ApplicationProvider

@RunWith(RobolectricTestRunner::class)
class SharedPrefTest {

    private lateinit var context: Context
    private lateinit var userRepo: UserRepo
    private lateinit var sharedPreferences: SharedPreferences

    @Before
    fun setup() {
        context = ApplicationProvider.getApplicationContext()
        userRepo = UserRepo(context)
    }

    @Test
    fun `check mocked instances are not null`() {
        context assertNotEquals null
        userRepo assertNotEquals null
    }

    @Test
    fun `when shared pref instance not null then do further ops`() {
        sharedPreferences = context.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE)
        sharedPreferences assertNotEquals null
    }

    companion object {
        const val USER_PREFS = "userprefs"
    }

}

参考:http://robolectric.org/androidx_test/

【讨论】: