Reputation: 2660
Consider below testing class:
@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))
)
}
}
Here is the Database class:
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
}
}
}
When the old Mockito library is being used (1.10.19), the test passes.
When switching mockito-core to 3.0.0, I get 2 deprecated warnings for: @RunWith(MockitoJUnitRunner::class)
and Matchers
. After solving these 2 deprecated warnings, I am expecting readSomeValue() to return "test" but readSomeValue() returns null
.
// testImplementation 'org.mockito:mockito-core:3.0.0'
testImplementation 'org.mockito:mockito-core:1.10.19'
Upvotes: 1
Views: 298
Reputation: 4912
After solving these 2 deprecated warnings [...]
Please also share how you resolved these warnings. Because when I change:
Matchers.eq(DatabaseManager.SOME_UNIQUE_KEY),
Matchers.anyString()
to
eq(DatabaseManager.SOME_UNIQUE_KEY),
any<String>()
and delete the line
`when`(mockEditor?.commit()).thenReturn(true)
to remove an error about unused mocking, then the test pass for me with org.mockito:mockito-core:3.0.0
.
Upvotes: 0
Reputation: 1767
First of all you should change the first bit of your test as shown below:
@Mock
lateinit var mockSharedPreferences: SharedPreferences
@Mock
lateinit var mockEditor: SharedPreferences.Editor
@Before
fun initMocks() {
MockitoAnnotations.initMocks(this)
mockDatabaseManager = createMockSharedPreference()
}
You are not initialising your mock objects which hence the member variables are not assigned values.
Second of all, SharedPreferences is an android component and cannot be unit tested the way you are trying to. In your case you are trying to insert something, test the response of your insert function which is always true anyway. Then, you are trying to fetch that value. You shouldn't test the framework but your code.
If you want to do structure your tests like that, I will recommend Robolectric.
I will suggest structuring your tests differently though, like verifying that the right thing is called when you are expecting to. For example,
@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()
)
}
Upvotes: 1