android - 将 mockito-core 更新到版本 3.0.0 后,Mockito 在 SharedPreferences 中返回 null

标签 android unit-testing kotlin mockito

考虑下面的测试类:

@RunWith(MockitoJUnitRunner::class)
class DatabaseManagerTest {

    private var someStringValue = "test"
    private var mockDatabaseManager: DatabaseManager? = null
    @Mock
    internal var mockSharedPreferences: SharedPreferences? = null
    @Mock
    internal var mockEditor: SharedPreferences.Editor? = null

    @Before
    fun initMocks() {
         mockDatabaseManager = createMockSharedPreference()        
    }

    private fun createMockSharedPreference(): DatabaseManager {
        `when`<String>(
            mockSharedPreferences?.getString(
               Matchers.eq(DatabaseManager.SOME_UNIQUE_KEY),
               Matchers.anyString()
            )
        ).thenReturn(someStringValue)

        `when`(mockEditor?.commit()).thenReturn(true)

        `when`<SharedPreferences.Editor>(mockSharedPreferences?.edit()).thenReturn(mockEditor)

        return DatabaseManager(mockSharedPreferences!!)
    }

    @Test
    fun sharedPreferencesHelperUpdateAndReadStoredInformation() {
        val success = mockDatabaseManager?.insert(someStringValue)

        assertThat(
            "Checking that update method returns true",
            success, `is`(true)
        )

        val savedSharedPreferenceEntry = mockDatabaseManager?.readSomeValue()

        assertThat(
           "Checking that value is stored correctly",
           someStringValue,
           `is`(equalTo(savedSharedPreferenceEntry))
        )
    }
}

这是数据库类:

class DatabaseManager(private val preferences: SharedPreferences) {

    companion object {
        const val SOME_UNIQUE_KEY = "some_unique_key"
    }

    fun insert(response: String): Boolean {
        try {
            val editor = preferences.edit()
            editor.putString(SOME_UNIQUE_KEY, response)
            editor.apply()

        } catch (e: Exception) {
            e.printStackTrace()
        }
        return true
    }

    fun readSomeValue(): String? {
        return try {
            val someValue = preferences.getString(SOME_UNIQUE_KEY, null)
            someValue

        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }
}

当使用旧的 Mockito 库(1.10.19)时,测试通过。

将 mockito-core 切换到 3.0.0 时,我收到 2 个已弃用的警告:@RunWith(MockitoJUnitRunner::class)Matchers。解决了这 2 个已弃用的警告后,我期望 readSomeValue() 返回“test”,但 readSomeValue() 返回 null

//    testImplementation 'org.mockito:mockito-core:3.0.0'
    testImplementation 'org.mockito:mockito-core:1.10.19'

最佳答案

首先,您应该更改测试的第一位,如下所示:

@Mock
lateinit var mockSharedPreferences: SharedPreferences
@Mock
lateinit var mockEditor: SharedPreferences.Editor

@Before
fun initMocks() {
    MockitoAnnotations.initMocks(this)
    mockDatabaseManager = createMockSharedPreference()
}

您没有初始化您的模拟对象,因此没有为成员变量赋值。

其次,SharedPreferences 是一个 android 组件,无法按照您尝试的方式进行单元测试。在您的情况下,您正在尝试插入一些东西,测试您的 insert 函数的响应,它始终是 true 。然后,您正在尝试获取该值。您不应该测试框架,而应该测试您的代码。

如果你想像那样构建你的测试,我会推荐 Robolectric .

不过,我会建议以不同的方式构建您的测试,例如验证是否在您期望的时候调用了正确的东西。例如,

@Test
fun `shared preferences insert`() {
    mockDatabaseManager?.insert(someStringValue)

    Mockito.verify(mockSharedPreferences).edit()
    Mockito.verify(mockEditor).putString(
        Mockito.eq(DatabaseManager.SOME_UNIQUE_KEY),
        Mockito.eq(someStringValue)
    )
    Mockito.verify(mockEditor).apply()
}


@Test
fun `shared preferences readSomeValue`() {
    mockDatabaseManager?.readSomeValue()

    Mockito.verify(mockSharedPreferences).getString(
        Mockito.eq(DatabaseManager.SOME_UNIQUE_KEY),
        Mockito.isNull()
    )
}

关于android - 将 mockito-core 更新到版本 3.0.0 后,Mockito 在 SharedPreferences 中返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58205389/

相关文章:

kotlin - 使用功能构建器进行类型推断

android - Android 上的 Webrtc 静态库

java - JUnit @Before 和@After 在每次测试之前和之后执行

unit-testing - Golang 单元测试

kotlin - Kotlin/Native 中的 ${type}Var 是什么?

android - 测试 Android Kotlin 应用程序 - 使用 Dagger 的 Mockito 注入(inject) null

android - IntentService 和 HandlerThread 计数

android - 从MapActivity中选择Address并返回MainActivity

android - 测试 Activity onCreate Exception

unit-testing - Kentico 9 的单元测试项目测试在测试资源管理器中不可见