https://kotlinlang.org logo
#compose
Title
# compose
g

Gabriel

11/04/2020, 8:01 PM
Hey folks, I'm using mockito to mock a viewmodel and then return certain values, my view model contains this where imageItems is
Copy code
var imageItems: List<ImageItem> by mutableStateOf(listOf())
	private set
and then my mock looks like this
Copy code
@Mock
lateinit var viewModel: ImageListViewModel
...

`when`(viewModel.imageItems).thenReturn(listOf())
but doing this gives me an error:
Copy code
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object androidx.compose.runtime.State.getValue()' on a null object reference
would anyone know what I'm doing wrong?
If I try skipping the mocking of the values I now instead get
Copy code
java.lang.IllegalArgumentException: Cannot skip the enclosing group while in an empty region
	at androidx.compose.runtime.SlotReader.skipToGroupEnd(SlotTable.kt:222)
z

Zach Klippenstein (he/him) [MOD]

11/04/2020, 10:30 PM
I would use StateFlow in your view model instead of MutableState, it will probably much more straightforward to mock since it doesn't depend on all the snapshot magic in compose.
💡 1
Then in compose you can call collectAsState to convert it to a State
g

Gabriel

11/05/2020, 7:45 AM
OK I'll have a look at that, thanks @Zach Klippenstein (he/him) [MOD]
@Zach Klippenstein (he/him) [MOD] still the same/similar problem:
Copy code
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object kotlinx.coroutines.flow.StateFlow.getValue()' on a null object reference
	at co.g403.android.minderachallengev3.imageList.ImageListScreenKtTest.imageListScreen(ImageListScreenKtTest.kt:29)
	at java.lang.reflect.Method.invoke(Native Method)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
Copy code
`when`(viewModel.isLoading.value).thenReturn(false)
Copy code
private val _isLoading = MutableStateFlow(false)
	val isLoading: StateFlow<Boolean>
		get() = _isLoading
z

Zach Klippenstein (he/him) [MOD]

11/05/2020, 6:52 PM
Don't provide mocks for the members of the StateFlow, just provide a MutableStateFlow to your ViewModel mock
g

Gabriel

11/05/2020, 6:54 PM
@Zach Klippenstein (he/him) [MOD] sorry could you explain that a bit more?
z

Zach Klippenstein (he/him) [MOD]

11/05/2020, 6:57 PM
Don't do
when(viewModel.isLoading.value).the return(false)
, instead do:
Copy code
private val isLoading = MutableStateFlow(false)
…
when(viewModel.isLoading).thenReturn(isLoading)
And just configure your fake loading value using the regular MutableStateFlow API
g

Gabriel

11/05/2020, 6:58 PM
OK, thanks I'll give that a try!
Copy code
org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
72 Views