تكرار السؤال: …
الإجابة المختصرة
باستخدام runTest التي تقفز تلقائيًا عبر تأخيرات الوقت (delay skipping)، واستبدال Dispatchers.Main بموزع اختبار عبر Dispatchers.setMain.
الشرح
بدون runTest، فإن استدعاء دالة تحتوي على delay(10_000L) سيجعل الاختبار ينتظر 10 ثوانٍ حقيقية. تقوم بيئة runTest بالتحكم في Virtual Time والقفز التلقائي للوقت الافتراضي. يوفر StandardTestDispatcher جدولة يدوية للمهام عبر advanceUntilIdle() أو advanceTimeBy()، بينما ينفذ UnconfinedTestDispatcher المهام الجديدة بشغف فوري دون انتظار.
مثال بالكود
@OptIn(ExperimentalCoroutinesApi::class)
class CoroutineTest {
private val testDispatcher = StandardTestDispatcher()
@Before
fun setUp() { Dispatchers.setMain(testDispatcher) }
@After
fun tearDown() { Dispatchers.resetMain() }
@Test
fun delayedOperation_completesImmediately() = runTest(testDispatcher) {
val deferred = async { delay(5000L); "Done" }
advanceUntilIdle() // يقفز عبر 5 ثوانٍ افتراضية في جزء من الميلي ثانية!
assertEquals("Done", deferred.getCompleted())
}
}أخطاء شائعة
- نسيان استدعاء Dispatchers.setMain في بداية الاختبارات التي تستخدم viewModelScope، مما يسبب كراش IllegalStateException لفقدان Looper الخيط الرئيسي.