Testing ViewModels helps ensure your app's data logic works correctly without needing the full app UI. It catches bugs early and makes your app more reliable.
ViewModel testing in Android Kotlin
class MyViewModelTest {
private lateinit var viewModel: MyViewModel
@Before
fun setup() {
viewModel = MyViewModel()
}
@Test
fun testExample() {
// test code here
}
}Use @Before to set up your ViewModel before each test.
Use @Test to mark functions that run as tests.
increment() increases the count LiveData value by 1.class CounterViewModelTest { private lateinit var viewModel: CounterViewModel @Before fun setup() { viewModel = CounterViewModel() } @Test fun increment_increasesCount() { viewModel.increment() assertEquals(1, viewModel.count.value) } }
loginSuccess LiveData to true.class LoginViewModelTest { private lateinit var viewModel: LoginViewModel @Before fun setup() { viewModel = LoginViewModel() } @Test fun login_withValidCredentials_setsSuccess() { viewModel.login("user", "pass") assertEquals(true, viewModel.loginSuccess.value) } }
This example shows a simple ViewModel with a count LiveData and an increment function. The test checks that calling increment updates the count from 0 to 1.
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class SimpleViewModel : ViewModel() { val count = MutableLiveData(0) fun increment() { count.value = (count.value ?: 0) + 1 } } // Test class import org.junit.Before import org.junit.Test import org.junit.Assert.assertEquals class SimpleViewModelTest { private lateinit var viewModel: SimpleViewModel @Before fun setup() { viewModel = SimpleViewModel() } @Test fun increment_increasesCount() { viewModel.increment() assertEquals(1, viewModel.count.value) } }
Use MutableLiveData to hold data in ViewModel that can change.
Use assertEquals(expected, actual) to check if your test result matches what you expect.
Tests run quickly and do not need the full Android UI to work.
ViewModel testing checks your app's data logic without UI.
Use @Before to prepare your ViewModel before tests.
Use assertions like assertEquals to verify expected results.
Practice
What is the main purpose of testing a ViewModel in Android development?
Solution
Step 1: Understand ViewModel role
The ViewModel holds and manages UI-related data but does not handle UI rendering.Step 2: Identify testing focus
Testing ViewModel focuses on data logic and state management, not UI or navigation.Final Answer:
To verify the data handling and business logic without UI involvement -> Option BQuick Check:
ViewModel testing = data logic check [OK]
- Confusing ViewModel testing with UI testing
- Thinking ViewModel tests check screen layouts
- Assuming navigation is tested in ViewModel tests
Which annotation is commonly used to set up a ViewModel instance before each test method runs?
Solution
Step 1: Recall JUnit lifecycle annotations
@Before runs before each test method to prepare test environment.Step 2: Match annotation to ViewModel setup
Use @Before to initialize ViewModel before tests run.Final Answer:
@Before -> Option DQuick Check:
Setup before tests = @Before [OK]
- Using @Test instead of @Before for setup
- Confusing @After with setup annotation
- Skipping setup annotation entirely
Given the following test code snippet, what will be the value of result after running the test?
class MyViewModelTest {
private lateinit var viewModel: MyViewModel
@Before
fun setup() {
viewModel = MyViewModel()
}
@Test
fun testIncrement() {
viewModel.increment()
val result = viewModel.counter
}
}Assuming counter starts at 0 and increment() adds 1.
Solution
Step 1: Understand initial state
ViewModel's counter starts at 0 before increment.Step 2: Apply increment method
Calling increment() adds 1, so counter becomes 1.Final Answer:
1 -> Option AQuick Check:
Initial 0 + 1 increment = 1 [OK]
- Assuming counter remains 0 after increment
- Thinking result is null without initialization
- Expecting an exception without error in code
Identify the error in this ViewModel test code snippet:
class SampleViewModelTest {
private lateinit var viewModel: SampleViewModel
@Test
fun testReset() {
viewModel.reset()
assertEquals(0, viewModel.counter)
}
}Assuming viewModel is not initialized anywhere else.
Solution
Step 1: Check viewModel initialization
viewModel is declared but never initialized before test runs.Step 2: Identify missing setup
Without @Before method to initialize viewModel, calling reset() causes error.Final Answer:
Missing @Before setup to initialize viewModel before test -> Option AQuick Check:
Initialize viewModel before test = @Before needed [OK]
- Forgetting to initialize viewModel before use
- Mixing assertEquals parameter order
- Assuming reset() method is missing without checking
You want to test a ViewModel method that fetches data asynchronously and updates a LiveData property. Which approach is best to test this behavior?
Solution
Step 1: Understand asynchronous data fetching
ViewModel uses coroutines to fetch data and update LiveData asynchronously.Step 2: Use coroutine test tools
Coroutine test rules allow running suspend functions in tests synchronously for reliable assertions.Step 3: Observe LiveData changes properly
Observing LiveData synchronously ensures test waits for updates before asserting values.Final Answer:
Use a coroutine test rule to run suspend functions and observe LiveData changes synchronously -> Option CQuick Check:
Async ViewModel test = coroutine test rule + LiveData observe [OK]
- Checking LiveData immediately without waiting
- Mocking LiveData instead of testing real updates
- Testing UI instead of ViewModel logic
Ready to prove it?
Pass the test and this pattern moves unknown
