saitho saitho - 3 years ago 73
Android Question

Mocked method not returning value from test-local variable

I have written a test to check if my method for adding and subtracting coins from the userdata preference method is working correctly. I mocked the SharedPreferences class and I am using a local variable

coins
that stores the coin amount.

However the mocked getInt() does not seem to return the correct value of coins:
Running the test addCoinValid fails (Expected: 5, Actual: 0). I've made 2 outputs during the test:

variable: 1 - mockedReturn: 0

variable: 5 - mockedReturn: 0

The left number is the value from the variable and the right number is what the mocked getInt() returns.

Can anyone tell me what's going on? :O




This is my test:

class UserDataTest {
var coins = 0

val editor = mock<SharedPreferences.Editor>()
val sharedPrefs = mock<SharedPreferences> {
on{ getInt("coins", 0) } doReturn coins
on { edit() } doReturn editor
}
val context = mock<Context> {
on { getSharedPreferences("userdata", 0) } doReturn sharedPrefs
}
val userData = UserData(context)

@Before
fun initEditorMock() {
whenever(editor.clear()).thenReturn(editor)
whenever(editor.putInt(eq("coins"), any<Int>())).thenAnswer{ invocation ->
this.coins = invocation.getArgument(1)
return@thenAnswer editor
}
}

@Test
fun addCoinValid() {
userData.setCoins(1)
println("variable: "+coins+" - mockedReturn: "+userData.getCoins())

userData.addCoins(5)
println("variable: "+coins+" - mockedReturn: "+userData.getCoins())
assertEquals(5, userData.getCoins())
}
// ...
}


And this is the class that is tested:

class UserData(context: Context) {
val settings = context.getSharedPreferences("userdata", 0)

fun getCoins(): Int {
return settings.getInt("coins", 0)
}

fun setCoins(number: Int) {
settings.edit().clear().putInt("coins", number).apply()
}

fun addCoins(number: Int) {
if(number < 0) {
return
}
var coins = settings.getInt("coins", 0)
setCoins(coins+number)
}
}

Answer Source

When you use doReturn coins, Mockito saves the value that coins had at the mock set up time, that is, its initial value 0, and then returns that saved value ignoring the changes to the actual variable.

To make the mock query the variable each time the function is called, use doAnswer { ... }:

on { getInt("coins", 0) } doAnswer { coins }
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download