Android Academy · درس

المحاكاة باستخدام Mockito

اعزلوا التبعيات باستخدام Mockito وMockK. حدّدوا قيم الإرجاع، وتحقّقوا من التفاعلات، والتقطوا الوسائط، واستخدموا spies للمحاكاة الجزئية.

الدرس 2 من 414 خطوة

المحاكاة باستخدام Mockito درس مجاني في Android Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Android Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Android Academy 4 دروس في المجموع.

ما المقصود بالمحاكاة؟

إن mock كائن مزيف يستبدل اعتمادًا حقيقيًا في الاختبارات. وعلى خلاف Fake، وهو تنفيذ عملي داخل الذاكرة، فإن mock:

  • تُنشئه مكتبة تلقائيًا
  • يسجل الدوال التي استُدعيت والوسائط التي استُخدمت معها
  • يعيد أي قيمة تحددها له (stubbing)
  • يتيح لك التحقق من التفاعلات بعد الاختبار

إعداد Mockito

أضف Mockito وMockK، وهو بديل يركّز على Kotlin، إلى app/build.gradle:

// app/build.gradle:
testImplementation 'org.mockito:mockito-core:5.10.0'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.2.1'

// MockK (Kotlin-idiomatic alternative to Mockito):
testImplementation 'io.mockk:mockk:1.13.10'

إنشاء Mocks

أنشئ Mocks باستخدام mock() أو التعليق التوضيحي @Mock:

import org.mockito.kotlin.*

interface UserApi {
    suspend fun fetchUsers(): List<User>
    suspend fun deleteUser(id: Int)
}

class RepositoryTest {

    // Option 1: create inline
    private val api: UserApi = mock()

    // Option 2: use annotation + MockitoJUnit4Runner
    @Mock lateinit var api2: UserApi

    @get:Rule
    val mockitoRule = MockitoJUnit.rule()
}

Stubbing — تحديد القيم المعادة

استخدم whenever(mock.method()).thenReturn(value) لتحديد القيمة التي يعيدها mock:

val api: UserApi = mock()

// Stub a return value:
whenever(api.fetchUsers()).thenReturn(
    listOf(User(1, "Alice"), User(2, "Bob"))
)

// Stub an exception:
whenever(api.fetchUsers()).thenThrow(RuntimeException("Network error"))

// Return different values on consecutive calls:
whenever(api.fetchUsers())
    .thenReturn(emptyList())           // first call
    .thenReturn(listOf(User(1, "Alice"))) // second call

verify() — التحقق من التفاعلات

استخدم verify() للتأكد من استدعاء دالة ما، وكذلك عدد مرات استدعائها:

val api: UserApi = mock()
val repo = UserRepository(api)

repo.refreshUsers()

// Verify that fetchUsers() was called exactly once:
verify(api).fetchUsers()

// Verify called with specific argument:
repo.deleteUser(42)
verify(api).deleteUser(42)

// Verify called exactly 3 times:
verify(api, times(3)).fetchUsers()

// Verify never called:
verify(api, never()).deleteUser(any())

ArgumentCaptor

يلتقط ArgumentCaptor الوسيط المُمرر إلى دالة mock، لكي تتمكن من التأكد من قيمته:

val api: UserApi = mock()
val captor = argumentCaptor<User>()

val repo = UserRepository(api)
repo.saveUser(User(1, "Alice"))

verify(api).saveUser(captor.capture())

val captured = captor.firstValue
assertEquals(1, captured.id)
assertEquals("Alice", captured.name)

MockK — محاكاة تركز على Kotlin

صُمم MockK خصيصًا لـ Kotlin، ويتعامل أصليًا مع دوال الامتداد وcoroutines والكائنات:

import io.mockk.*

val api = mockk<UserApi>()

// Stub:
every { api.fetchUsers() } returns listOf(User(1, "Alice"))

// Stub suspend function:
coEvery { api.fetchUsers() } returns listOf(User(1, "Alice"))

// Verify:
val repo = UserRepository(api)
runBlocking { repo.refresh() }
coVerify { api.fetchUsers() }

محاكاة Coroutines باستخدام MockK

استخدم coEvery وcoVerify مع الدوال المعلّقة:

val api = mockk<UserApi>()

// Stub suspend function:
coEvery { api.fetchUsers() } returns listOf(User(1, "Alice"))
coEvery { api.deleteUser(any()) } just Runs  // returns Unit

// Test:
runTest {
    val repo = UserRepository(api)
    repo.refresh()
    coVerify(exactly = 1) { api.fetchUsers() }
    coVerify(exactly = 0) { api.deleteUser(any()) }
}

Spy — محاكاة جزئية

يغلّف spy كائنًا حقيقيًا. وتُستدعى الدوال الحقيقية افتراضيًا ما لم تُستبدل:

// Mockito Spy:
val realList = mutableListOf("a", "b", "c")
val spyList = spy(realList)

// Real method called:
spyList.add("d")
assertEquals(4, spyList.size)   // real add() was called

// Override specific method:
doReturn(99).`when`(spyList).size
assertEquals(99, spyList.size)  // overridden

// MockK Spy:
val spyObj = spyk(RealService())
every { spyObj.expensiveCall() } returns "fake result"

متى تستخدم Mocks بدلًا من Fakes؟

إرشادات عملية:

  • استخدم Fake عندما تحتاج إلى تنفيذ عملي داخل الذاكرة، مثل DAO أو المستودع؛ فهو أسهل قراءة ولا يحتاج إلى مكتبة.
  • استخدم Mock عندما تحتاج إلى التحقق من استدعاء دالة محددة بوسائط محددة، مثل أحداث التحليلات أو استدعاءات API.
  • تجنب الإفراط في استخدام Mocks — فإذا حاكيت كل شيء، فستتحقق اختباراتك من صحة Mocks لا من منطقك.

الأخطاء الشائعة

أخطاء يجب تجنبها عند استخدام المحاكاة:

  • محاكاة كائنات القيم — حاكِ الواجهات/التجريدات، لا فئات البيانات
  • المحاكاة بعمق زائد — إذا احتجت إلى 5 Mocks في اختبار واحد، فالشيفرة مترابطة بشدة
  • عدم التحقق عندما يكون التفاعل مهمًا — لا تكتفِ بتحديد السلوك، بل تحقّق أيضًا
  • الإعدادات الافتراضية لـ Mockito + Kotlin — تكون وسائط Kotlin غير قابلة للقيمة الفارغة افتراضيًا؛ استخدم mockito-kotlin أو MockK لتجنب مفاجآت null

محاكاة الكائنات والكائنات المرافقة

يمكن لـ MockK محاكاة كائنات Kotlin والكائنات المرافقة، وهو أمر مستحيل باستخدام Mockito:

object DateProvider {
    fun today(): String = "2024-01-01"
}

// In test:
mockkObject(DateProvider)
every { DateProvider.today() } returns "2099-12-31"

val result = DateProvider.today()
assertEquals("2099-12-31", result)

// Restore after test:
unmockkObject(DateProvider)

تحقق سريع

ما الغرض من verify() في اختبار Mockito أو MockK؟

مراجعة: المحاكاة باستخدام Mockito وMockK

تتيح لك Mocks عزل السلوك والتحقق منه:

  • mock() / mockk() — إنشاء mock من واجهة أو فئة
  • whenever(...).thenReturn(...) / every { } returns ... — تحديد القيم المعادة
  • coEvery / coVerify — للدوال المعلّقة في Kotlin باستخدام MockK
  • verify(mock).method(args) — التأكد من استدعاء الدالة
  • ArgumentCaptor — التقاط الوسائط وفحصها
  • spy() / spyk() — محاكاة جزئية لكائن حقيقي
  • فضّل Fakes للبيانات، واستخدم Mocks للتحقق من السلوك

التالي: اختبار واجهة المستخدم باستخدام Espresso.

البدء مجانًا

تعلم Kotlin مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
36
الدروس
152

الأسئلة الشائعة

هل درس «المحاكاة باستخدام Mockito» مجاني؟

نعم — نص درس «المحاكاة باستخدام Mockito» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Android Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Android Academy 4 دروس في المجموع.

ماذا ستتعلم في «المحاكاة باستخدام Mockito»؟

اعزلوا التبعيات باستخدام Mockito وMockK. حدّدوا قيم الإرجاع، وتحقّقوا من التفاعلات، والتقطوا الوسائط، واستخدموا spies للمحاكاة الجزئية. تتمرن على Android Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Android Academy؟

لا تُشترط خبرة سابقة. Android Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «المحاكاة باستخدام Mockito»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Android Academy هذا؟

نعم. كل درس في Android Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. اختبار الوحدات باستخدام JUnit
  2. المحاكاة باستخدام Mockito
  3. اختبار الواجهة باستخدام Espresso
  4. تصحيح الأخطاء وتحليل الأداء
← العودة إلى Android Academy