0
0
Android Kotlinmobile~20 mins

ViewModel testing in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: CounterViewModelTest
Test a simple ViewModel that holds a counter value and increments it.
Target UI
-------------------
| Counter: 0      |
| [Increment]     |
-------------------
Create a ViewModel with a LiveData<Int> counter starting at 0
Add a function to increment the counter
Write a unit test to verify the initial counter value is 0
Write a unit test to verify the counter increments correctly
Starter Code
Android Kotlin
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class CounterViewModel : ViewModel() {
    private val _counter = MutableLiveData<Int>(0)
    val counter: LiveData<Int> = _counter

    // TODO: Add increment function here
}
Task 1
Task 2
Task 3
Task 4
Solution
Android Kotlin
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class CounterViewModel : ViewModel() {
    private val _counter = MutableLiveData<Int>(0)
    val counter: LiveData<Int> = _counter

    fun increment() {
        val current = _counter.value ?: 0
        _counter.value = current + 1
    }
}

// Test file
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify

class CounterViewModelTest {
    @get:Rule
    val instantExecutorRule = InstantTaskExecutorRule()

    private lateinit var viewModel: CounterViewModel
    private lateinit var observer: Observer<Int>

    @Before
    fun setup() {
        viewModel = CounterViewModel()
        observer = mock(Observer::class.java) as Observer<Int>
        viewModel.counter.observeForever(observer)
    }

    @Test
    fun initialCounterIsZero() {
        assertEquals(0, viewModel.counter.value)
    }

    @Test
    fun incrementIncreasesCounter() {
        viewModel.increment()
        assertEquals(1, viewModel.counter.value)
        viewModel.increment()
        assertEquals(2, viewModel.counter.value)
    }
}

This ViewModel holds a counter as LiveData starting at 0. The increment() function increases the counter by 1 safely handling null values. The unit test uses InstantTaskExecutorRule to run LiveData synchronously. It observes the LiveData with a mocked observer to avoid leaks. The tests check the initial value is zero and that calling increment() updates the counter correctly.

Final Result
Completed Screen
-------------------
| Counter: 0      |
| [Increment]     |
-------------------
When user taps Increment button, counter value increases by 1
UI updates to show new counter value
Stretch Goal
Add a decrement function and test it decreases the counter but never below zero
💡 Hint
Check current counter value before decrementing and write a test to verify it does not go below zero