I am writing Junit tests for ViewModel, but mutableLiveData values are not update after test run and tests are failing.
View model has Dagger dependency injected class, hence I can not create viewmodel instance directly it has be mocked viewmodel instance.
qrInfoViewModel.mScreenType.value
and qrInfoViewModel.mQRCodeImage.value
is not updating after execution.
Please guide. Thanks in advance.
ViewModel Class
class QrInfoViewModel(val context: Context) : ViewModel() {
@Inject
lateinit var remoteAuthManager: RemoteAuthManager
@Inject
lateinit var authenticationManager: AuthenticationManager
@Inject
lateinit var rcpNetworkUtils: RcpNetworkUtils
@Inject
lateinit var navigationManager: NavigationManager
var mQRCodeImage: MutableLiveData<Bitmap> = MutableLiveData()
var mPortalCode: MutableLiveData<String> = MutableLiveData()
var mScreenType: MutableLiveData<Int> = MutableLiveData(QrInfoFragment.ScreenType.QR_INFO.value)
private var currentQRCode: String = ""
private var currentPortalCode: String = ""
init {
App.appComponent.inject(this)
}
fun handleButtonClick() {
//check screen type and do handling
when (mScreenType.value) {
QrInfoFragment.ScreenType.QR_INFO.value -> {
mQRCodeImage.value = generateQRCode()
mScreenType.value = QrInfoFragment.ScreenType.QR_CODE.value
}
QrInfoFragment.ScreenType.QR_CODE.value -> {
//refresh qr code
mScreenType.value = QrInfoFragment.ScreenType.QR_CODE.value
mQRCodeImage.value = generateQRCode()
}
QrInfoFragment.ScreenType.QR_SUCCESS.value -> {
//Navigate to set up pin screen
navigationManager.navigate(
R.id.qrInfoFragment,
QrInfoFragmentDirections.actionQrInfoFragmentToSetupPinFragment()
)
}
QrInfoFragment.ScreenType.PORTAL_INFO.value -> {
//Generate Portal code
mPortalCode.value = generatePortalCode()
//Reset expiry timer
mScreenType.value = QrInfoFragment.ScreenType.PORTAL_CODE.value
}
QrInfoFragment.ScreenType.PORTAL_CODE.value -> {
//Refresh portal code
//Reset expiry timer
mPortalCode.value = generatePortalCode()
mScreenType.value = QrInfoFragment.ScreenType.PORTAL_CODE.value
}
}
}
}
Junit Test Class
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(MockitoJUnitRunner.Silent::class)
class QrInfoViewModelTest {
@Mock
lateinit var appComponent: AppComponent
@Mock
private lateinit var informationDialogBinding: InformationDialogBinding
@Mock
lateinit var remoteAuthManager: RemoteAuthManager
@Mock
lateinit var navigationManager: NavigationManager
@Mock
lateinit var context: Context
@Mock
lateinit var confirmationOverlay: ConfirmationOverlay
@Mock
lateinit var qrInfoViewModel: QrInfoViewModel
@Mock
private lateinit var titleDialog: TextView
@Mock
private lateinit var messageDialog: TextView
@Mock
private lateinit var button: Button
@Mock
private lateinit var layoutInflater: LayoutInflater
// Sets the main coroutines dispatcher to a TestCoroutineScope for unit testing.
@ExperimentalCoroutinesApi
@get:Rule
var mainCoroutineRule = MainDispatcherRule()
// Run tasks synchronously
@Rule
@JvmField
val instantTaskExecutorRule = InstantTaskExecutorRule()
private var isLogin = true
private var isShowSuccessDialog = true
private var response = RemoteAuthManager.ResponseStatus(RemoteAuthManager.Status.Success)
@Before
fun setup() = runTest{
Logger.init("", "")
App.appComponent = appComponent
Mockito.`when`(
remoteAuthManager.loginUsingQRCode(
ArgumentMatchers.anyString(),
ArgumentMatchers.anyString(),
ArgumentMatchers.anyString(),
ArgumentMatchers.anyString()
)
).then {
isLogin = true
response
}
mockkObject(DialogHelper)
every {
DialogHelper.showInformationDialog(
context,
"message",
"message",
okButtonText = "message"
)
}
Mockito.`when`(context.getString(ArgumentMatchers.anyInt())).thenReturn("")
informationDialogBinding.setPrivateProperty("titleDialog", titleDialog)
informationDialogBinding.setPrivateProperty("messageDialog", messageDialog)
informationDialogBinding.setPrivateProperty("okButton", button)
Mockito.`when`(titleDialog.setText(ArgumentMatchers.anyString())).then {
null
}
Mockito.`when`(messageDialog.setText(ArgumentMatchers.anyString())).then {
null
}
mockkConstructor(ConfirmationOverlay::class)
Mockito.`when`(confirmationOverlay.setMessage(ArgumentMatchers.anyString() as CharSequence))
.then {
confirmationOverlay
}
Mockito.`when`(confirmationOverlay.setOnAnimationFinishedListener(MockUtils.anyObject()))
.then {
(it.arguments[0] as ConfirmationOverlay.OnAnimationFinishedListener).onAnimationFinished()
confirmationOverlay
}
every { anyConstructed<ConfirmationOverlay>().setType(ConfirmationOverlay.SUCCESS_ANIMATION) } answers ({
isShowSuccessDialog = true
confirmationOverlay
})
Mockito.`when`(context.getString(R.string.ok_button)).then { "message" }
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun handleButtonClickTest() = runTest {
//Case 1: QR_INFO Screen Type
Mockito.`when`(qrInfoViewModel.mScreenType)
.thenReturn(MutableLiveData<Int>(QrInfoFragment.ScreenType.QR_INFO.value))
qrInfoViewModel.mScreenType.value = QrInfoFragment.ScreenType.QR_INFO.value
Mockito.`when`(qrInfoViewModel.mQRCodeImage).thenReturn(MutableLiveData<Bitmap>())
qrInfoViewModel.mScreenType.observeForever{
Assert.assertEquals(
QrInfoFragment.ScreenType.QR_CODE.value,
qrInfoViewModel.mScreenType.getOrAwaitValue()
)
}
qrInfoViewModel.mQRCodeImage.observeForever {
Assert.assertNotNull(qrInfoViewModel.mQRCodeImage.getOrAwaitValue())
}
qrInfoViewModel.handleButtonClick()
runCurrent()
}
}