Skip to content

Snappy1

  • Home
  • Android
  • What
  • How
  • Is
  • Can
  • Does
  • Do
  • Why
  • Are
  • Who
  • Toggle search form

[FIXED] android – ViewModel unit tests fail when run together but pass when run individually

Posted on November 11, 2022 By

Solution 1 :

This might not be a complete answer because there is so much in your question. Start by trying to use a CoroutineTestRule:

@ExperimentalCoroutinesApi
class CoroutineTestRule(
    private val testDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()
) : TestWatcher() {

    override fun starting(description: Description?) {
        Dispatchers.setMain(testDispatcher)
    }

    override fun finished(description: Description?) {
        Dispatchers.resetMain()
        testDispatcher.cleanupTestCoroutines()
    }
}

Your test will be something like:

class PaymentViewModelTest : KoinTest {
    private val paymentViewModel : PaymentViewModel by inject()

    @get:Rule
    val coroutineTestRule = CoroutineTestRule()

    @Before
    fun setup(){
        startKoin {
            androidContext(mock(Application::class.java))
            modules(
                modules.repositoryModule,
                modules.businessModule,
                modules.utilsModule
            )
        }
        declareMock<AnalyticsHelper>()
        declareMock<Printer>()
    }

    @After
    fun after(){
        stopKoin()
    }

    // Other methods are the same.
}

You can use an AutoCloseKoinTest to remove that after() method.

You say that the test is passing when you run it isolated, so maybe this is enough. But there is more to dig into if this doesn’t work. For example, I find it strange that you use runBlockingTest inside a mock and the assert is outside that block. Usually I would use MockK to mock suspending functions and test and assert any of them inside a runBlockingTest.

Problem :

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)))
READ  [FIXED] android - How to get Activity that paused and goes in background?
Powered by Inline Related Posts
Android Tags:android, koin, kotlin-coroutines, unit-testing

Post navigation

Previous Post: [FIXED] Is it possible to switch from Start state to End state in android MotionLayout using Java/Kotlin?
Next Post: [FIXED] android – PHP / SQL: cannot save image at server but successful save image link at SQL database

Related Posts

[FIXED] android – How to access HttpServer on phone? Android
[FIXED] android – Is it possible to use Jenkins for Flutter? Android
[FIXED] android – Flutter App crashes emulator when opening camera Android
[FIXED] android – Flutter money text formatting with TextFormField Android
[FIXED] android – Verify ID Tokens: What is the workflow to use this Firebase checkment? Android
[FIXED] android – Flutter: Calculate the center point of an image Android

Archives

  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022

Categories

  • ¿Cómo
  • ¿Cuál
  • ¿Cuándo
  • ¿Cuántas
  • ¿Cuánto
  • ¿Qué
  • Android
  • Are
  • At
  • C'est
  • Can
  • Comment
  • Did
  • Do
  • Does
  • Est-ce
  • Est-il
  • For
  • Has
  • Hat
  • How
  • In
  • Is
  • Ist
  • Kann
  • Où
  • Pourquoi
  • Quand
  • Quel
  • Quelle
  • Quelles
  • Quels
  • Qui
  • Should
  • Sind
  • Sollte
  • Uncategorized
  • Wann
  • Warum
  • Was
  • Welche
  • Welchen
  • Welcher
  • Welches
  • Were
  • What
  • What's
  • When
  • Where
  • Which
  • Who
  • Who's
  • Why
  • Wie
  • Will
  • Wird
  • Wo
  • Woher
  • you can create a selvedge edge: You can make the edges of garter stitch more smooth by slipping the first stitch of every row.2022-02-04
  • you really only need to know two patterns: garter stitch

Recent Posts

  • What is the rising action in Julius Caesar?
  • How do you secure a rope to itself?
  • Does waterproof laminate scratch easily?
  • What makes a building prewar?
  • What can you learn in a month without alcohol?

Recent Comments

No comments to show.

Copyright © 2023 Snappy1.

Powered by PressBook Grid Dark theme