@@ -13,8 +13,10 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
1313import kotlinx.coroutines.Job
1414import kotlinx.coroutines.job
1515import kotlinx.coroutines.suspendCancellableCoroutine
16- import kotlinx.coroutines.test.TestCoroutineDispatcher
16+ import kotlinx.coroutines.test.StandardTestDispatcher
17+ import kotlinx.coroutines.test.UnconfinedTestDispatcher
1718import kotlinx.coroutines.test.resetMain
19+ import kotlinx.coroutines.test.runTest
1820import kotlinx.coroutines.test.setMain
1921import org.junit.After
2022import org.junit.Before
@@ -34,26 +36,22 @@ import org.mockito.kotlin.whenever
3436@OptIn(ExperimentalCoroutinesApi ::class , WorkflowUiExperimentalApi ::class )
3537internal class ViewLaunchWhenAttachedTest {
3638
37- private val dispatcher = TestCoroutineDispatcher ()
3839 private val view = mockView()
3940 private val onAttachStateChangeListener = argumentCaptor<OnAttachStateChangeListener >()
4041
4142 @Before
4243 fun setUp () {
43- Dispatchers .setMain(dispatcher )
44+ Dispatchers .setMain(StandardTestDispatcher () )
4445 }
4546
4647 @After fun tearDown () {
47- dispatcher.cleanupTestCoroutines()
4848 Dispatchers .resetMain()
4949 }
5050
51- @Test fun `launchWhenAttached launches synchronously when already attached` () {
51+ @Test fun `launchWhenAttached launches synchronously when already attached` () = runTest {
5252 var innerJob: Job ? = null
5353 var started = false
5454 mockAttachedToWindow(view, true )
55- // Pause the dispatcher to verify that the coroutine is started synchronously.
56- dispatcher.pauseDispatcher()
5755
5856 // Action: launch a coroutine!
5957 view.launchWhenAttached {
@@ -74,9 +72,8 @@ internal class ViewLaunchWhenAttachedTest {
7472 assertThat(innerJob!! .isCancelled).isTrue()
7573 }
7674
77- @Test fun `launchWhenAttached cancels when detached while launching` () {
75+ @Test fun `launchWhenAttached cancels when detached while launching` () = runTest {
7876 mockAttachedToWindow(view, true )
79- dispatcher.pauseDispatcher()
8077
8178 // Action: launch a coroutine!
8279 view.launchWhenAttached {
@@ -88,7 +85,7 @@ internal class ViewLaunchWhenAttachedTest {
8885 }
8986 }
9087
91- @Test fun `launchWhenAttached launches when attached later` () {
88+ @Test fun `launchWhenAttached launches when attached later` () = runTest {
9289 var innerJob: Job ? = null
9390 mockAttachedToWindow(view, false )
9491
@@ -99,14 +96,14 @@ internal class ViewLaunchWhenAttachedTest {
9996 }
10097 }
10198
102- dispatcher .advanceUntilIdle()
99+ testScheduler .advanceUntilIdle()
103100 assertThat(innerJob).isNull()
104101
105102 verify(view).setTag(isA(), isA<OnAttachStateChangeListener >())
106103
107104 // Action: attach view!
108105 performViewAttach()
109- dispatcher .advanceUntilIdle()
106+ testScheduler .advanceUntilIdle()
110107 assertThat(innerJob).isNotNull()
111108 assertThat(innerJob!! .isActive).isTrue()
112109
@@ -115,7 +112,7 @@ internal class ViewLaunchWhenAttachedTest {
115112 assertThat(innerJob!! .isCancelled).isTrue()
116113 }
117114
118- @Test fun `launchWhenAttached launches when reattached` () {
115+ @Test fun `launchWhenAttached launches when reattached` () = runTest {
119116 var innerJob: Job ? = null
120117 mockAttachedToWindow(view, true )
121118
@@ -131,7 +128,7 @@ internal class ViewLaunchWhenAttachedTest {
131128 }
132129
133130 // The coroutine shouldn't have started since the view is detached.
134- dispatcher .advanceUntilIdle()
131+ testScheduler .advanceUntilIdle()
135132 assertThat(innerJob).isNull()
136133
137134 // Action: re-attach view!
@@ -144,7 +141,7 @@ internal class ViewLaunchWhenAttachedTest {
144141 assertThat(innerJob!! .isActive).isTrue()
145142 }
146143
147- @Test fun `launchWhenAttached coroutine is child of ViewTreeLifecycleOwner` () {
144+ @Test fun `launchWhenAttached coroutine is child of ViewTreeLifecycleOwner` () = runTest {
148145 var innerJob: Job ? = null
149146 mockAttachedToWindow(view, true )
150147
@@ -154,6 +151,7 @@ internal class ViewLaunchWhenAttachedTest {
154151 innerJob = continuation.context.job
155152 }
156153 }
154+ testScheduler.advanceUntilIdle()
157155
158156 assertThat(innerJob!! .isActive).isTrue()
159157
@@ -164,7 +162,7 @@ internal class ViewLaunchWhenAttachedTest {
164162 assertThat(innerJob!! .isCancelled).isTrue()
165163 }
166164
167- @Test fun `launchWhenAttached includes view classname in coroutine name` () {
165+ @Test fun `launchWhenAttached includes view classname in coroutine name` () = runTest {
168166 var coroutineName: String? = null
169167 mockAttachedToWindow(view, true )
170168
@@ -178,7 +176,7 @@ internal class ViewLaunchWhenAttachedTest {
178176 assertThat(coroutineName).contains(" ${view.hashCode()} " )
179177 }
180178
181- @Test fun `launchWhenAttached includes view id name in coroutine name` () {
179+ @Test fun `launchWhenAttached includes view id name in coroutine name` () = runTest {
182180 var coroutineName: String? = null
183181 mockAttachedToWindow(view, true )
184182 whenever(view.resources.getResourceEntryName(anyInt())).thenReturn(" fnord" )
@@ -191,7 +189,7 @@ internal class ViewLaunchWhenAttachedTest {
191189 assertThat(coroutineName).contains(" fnord" )
192190 }
193191
194- @Test fun `launchWhenAttached tolerates garbage ids` () {
192+ @Test fun `launchWhenAttached tolerates garbage ids` () = runTest {
195193 var coroutineName: String? = null
196194 mockAttachedToWindow(view, true )
197195 whenever(view.resources.getResourceEntryName(anyInt())).thenThrow(NotFoundException ())
@@ -224,7 +222,7 @@ internal class ViewLaunchWhenAttachedTest {
224222 return mock<View >(defaultAnswer = RETURNS_DEEP_STUBS ).also {
225223 mockTags(it)
226224 mockAttachedToWindow(it)
227- ViewTreeLifecycleOwner .set(it, TestLifecycleOwner (coroutineDispatcher = dispatcher ))
225+ ViewTreeLifecycleOwner .set(it, TestLifecycleOwner (coroutineDispatcher = UnconfinedTestDispatcher () ))
228226 }
229227 }
230228
0 commit comments