I am testing a suspended method from my ViewModel that triggers LiveData to emit an object when coroutine is completed. When
I run each of those tests individually they pass, when I run them together always the first test fails. Surprisingly, when I run them in debug and I put break points at assertValue to check what the vaule is, both of the test pass. My guess is that the problem is with the state of LiveData or the whole PaymentViewModel. What am I doing wrong?
class PaymentViewModelTest : KoinTest {
private val paymentViewModel : PaymentViewModel by inject()
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
private val mainThreadSurrogate = newSingleThreadContext("UI thread")
@Before
fun setup(){
Dispatchers.setMain(mainThreadSurrogate)
val modules = KoinModule()
startKoin {
androidContext(mock(Application::class.java))
modules(listOf(
modules.repositoryModule,
modules.businessModule,
modules.utilsModule)
)
}
declareMock<AnalyticsHelper>()
declareMock<Printer>()
}
@After
fun after(){
stopKoin()
Dispatchers.resetMain()
}
@Test
fun successfully_initializes_payment_flow() {
declareMock<PaymentRepository> {
runBlockingTest {
given(initPayment())
.willAnswer { InitPaymentResponse(0, PaymentStatus.INITIALIZED, 0) }
}
}
paymentViewModel.initPayment(BigDecimal(0))
paymentViewModel.paymentStatus.test()
.awaitValue()
.assertValue { value -> value.getContentIfNotHandled()?.data == PaymentStatus.INITIALIZED }
}
@Test
fun fails_to_initialize_payment_flow() {
declareMock<PaymentRepository> {
runBlockingTest {
given(initPayment())
.willThrow(MockitoKotlinException("", ConnectException()))
}
}
paymentViewModel.initPayment(BigDecimal(0))
paymentViewModel.paymentStatus.test()
.awaitValue()
.assertValue { value -> value.getContentIfNotHandled()?.status == ApiResponseStatus.ERROR}
}
}
Here is the method that I am testing:
fun initPayment(price: BigDecimal) {
paymentStatus.postValue(Event(ApiResponse.loading()))
viewModelScope.launch {
runCatching {
repository.initPayment()
}.onSuccess {
paymentSession = PaymentSession(it.paymentId)
paymentSession.price = price
postPaymentStatus(it.status)
}.onFailure {
postApiError(it)
}
}
}
private fun postPaymentStatus(status: PaymentStatus) =
paymentStatus.postValue(Event(ApiResponse.success(status)))