@@ -23,7 +23,11 @@ import com.android.example.livedatabuilder.util.MainCoroutineRule
23
23
import com.android.example.livedatabuilder.util.getOrAwaitValue
24
24
import com.android.example.livedatabuilder.util.observeForTesting
25
25
import kotlinx.coroutines.ExperimentalCoroutinesApi
26
- import kotlinx.coroutines.test.TestCoroutineDispatcher
26
+ import kotlinx.coroutines.test.TestDispatcher
27
+ import kotlinx.coroutines.test.advanceUntilIdle
28
+ import kotlinx.coroutines.test.runCurrent
29
+ import kotlinx.coroutines.test.runTest
30
+ import kotlinx.coroutines.yield
27
31
import org.junit.Assert.assertEquals
28
32
import org.junit.Assert.assertNotEquals
29
33
import org.junit.Assert.assertTrue
@@ -49,7 +53,7 @@ class LiveDataViewModelTest {
49
53
var mainCoroutineRule = MainCoroutineRule ()
50
54
51
55
// Use a Fake DataSource so we have all necessary control over it
52
- private val fakeDataSource = FakeDataSource ()
56
+ private val fakeDataSource = FakeDataSource (mainCoroutineRule.testDispatcher )
53
57
54
58
// Class under test. Uses Dispatchers.Main so that the MainCoroutineRule can control it.
55
59
private lateinit var viewModel: LiveDataViewModel
@@ -68,54 +72,56 @@ class LiveDataViewModelTest {
68
72
}
69
73
70
74
@Test
71
- fun currentTimeTransformed () {
75
+ fun currentTimeTransformed () = runTest {
72
76
// Get the result of a coroutine inside a transformation
73
77
val timeTransformed = viewModel.currentTimeTransformed.getOrAwaitValue {
74
78
// After observing, advance the clock to avoid the delay calls.
75
- mainCoroutineRule. advanceUntilIdle()
79
+ advanceUntilIdle()
76
80
}
77
- assertEquals(timeTransformed, Date (FakeDataSource .CURRENT_TIME ).toString())
81
+ assertEquals(Date (FakeDataSource .CURRENT_TIME ).toString(), timeTransformed )
78
82
}
79
83
80
84
@Test
81
- fun getCurrentWeather_loading () {
82
- // Start with a paused dispatcher in the FakeDataSource
83
- fakeDataSource.testDispatcher.pauseDispatcher()
84
-
85
+ fun getCurrentWeather_loading () = runTest {
85
86
// Keep observing currentWeather
86
87
viewModel.currentWeather.observeForTesting {
88
+ // Yield test thread so that the first LiveData emission can complete
89
+ yield ()
87
90
88
91
// Verify that the first value is Loading
89
- assertEquals(viewModel.currentWeather.value, LiveDataViewModel . LOADING_STRING )
92
+ assertEquals(LiveDataViewModel . LOADING_STRING , viewModel.currentWeather.value)
90
93
91
- // Resume fake dispatcher so it emits a new value
92
- fakeDataSource.testDispatcher.resumeDispatcher ()
94
+ // Execute all pending coroutines in the viewModel
95
+ runCurrent ()
93
96
94
97
// Verify the new value is available
95
- assertEquals(viewModel.currentWeather.value, FakeDataSource . WEATHER_CONDITION )
98
+ assertEquals(FakeDataSource . WEATHER_CONDITION , viewModel.currentWeather.value)
96
99
}
97
100
}
98
101
99
102
@Test
100
- fun cache_RefreshFromViewModelScope () {
103
+ fun cache_RefreshFromViewModelScope () = runTest {
101
104
// Get the initial value that comes directly from FakeDataSource
102
105
val initialValue = viewModel.cachedValue.getOrAwaitValue()
103
106
104
107
// Trigger an update, which starts a coroutine that updates the value
105
108
viewModel.onRefresh()
106
109
110
+ // Run pending coroutine in ViewModel
111
+ runCurrent()
112
+
107
113
// Get the new value
108
114
val valueAfterRefresh = viewModel.cachedValue.getOrAwaitValue()
109
115
110
116
// Assert they are different values
111
117
assertNotEquals(initialValue, valueAfterRefresh)
112
- assertEquals(initialValue, FakeDataSource .CURRENT_VALUE )
113
- assertEquals(valueAfterRefresh, FakeDataSource .NEW_VALUE )
118
+ assertEquals(FakeDataSource .CURRENT_VALUE , initialValue )
119
+ assertEquals(FakeDataSource .NEW_VALUE , valueAfterRefresh )
114
120
}
115
121
}
116
122
117
123
@ExperimentalCoroutinesApi
118
- class FakeDataSource : DataSource {
124
+ class FakeDataSource ( private val testDispatcher : TestDispatcher ) : DataSource {
119
125
120
126
companion object {
121
127
const val CURRENT_VALUE = " test"
@@ -129,7 +135,6 @@ class FakeDataSource : DataSource {
129
135
130
136
override fun getCurrentTime (): LiveData <Long > = MutableLiveData <Long >(CURRENT_TIME )
131
137
132
- val testDispatcher = TestCoroutineDispatcher ()
133
138
override fun fetchWeather (): LiveData <String > = liveData(testDispatcher) {
134
139
emit(WEATHER_CONDITION )
135
140
}
0 commit comments