اختبار في Kotlin: الوحدة، التكامل، E2E المستوى المتقدم

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا الاختبار المتقدم هو أساس كود Kotlin الموثوق

في تطوير Kotlin الحديث، كتابة الكود ليست سوى نصف المهمة. الإتقان الحقيقي يظهر في القدرة على إنشاء أنظمة موثوقة وقابلة للاختبار وسهلة الصيانة. اختبارات الوحدة الأساسية مألوفة للجميع، ولكن عندما ينمو المشروع إلى بنية الخدمات المصغرة أو منطق الأعمال المعقد، تصبح الفحوصات البسيطة غير كافية. يتضمن الاختبار المتقدم ليس فقط عزل الفئات، ولكن أيضًا التحقق من التفاعل بين المكونات (اختبارات التكامل) وإعادة إنتاج سيناريوهات المستخدم الكاملة (E2E).

هذه المقالة مخصصة للمطورين الذين هم بالفعل على دراية بأساسيات Kotlin ويريدون رفع جودة مشاريعهم إلى المستوى التالي. سنقوم بتحليل ثلاثة مستويات رئيسية للاختبار: الوحدة والتكامل و E2E، باستخدام أدوات حديثة: MockK و Testcontainers و Ktor Client. ستتعلم كيفية كتابة اختبارات لا "تنجح" فحسب، بل تحمي كودك حقًا من الانحدارات.



1. اختبار الوحدة: العزل والكائنات الوهمية مع MockK

اختبارات الوحدة هي أساس هرم الاختبار. على المستوى المتقدم، لا نتحقق فقط من الدوال، بل نختبر التفاعلات المعقدة بين الكائنات باستخدام الكائنات الوهمية. في Kotlin، أفضل مكتبة لذلك هي MockK.



1.1. الإمكانيات المتقدمة لـ MockK

على عكس Mockito، تمت كتابة MockK خصيصًا لـ Kotlin ويدعم coroutines و lambdas و extension-functions. لنلق نظرة على مثال لاختبار خدمة تستخدم مستودعًا و coroutines:

// الخدمة المراد اختبارهاclass UserService(private val repo: UserRepository) {    suspend fun getUserName(id: Long): String {        val user = repo.findById(id)        return user?.name ?: "Unknown"    }}

// الاختبارclass UserServiceTest { private val repo = mockk<UserRepository>() private val service = UserService(repo)

@Test fun `should return user name when user exists`() = runTest { // given coEvery { repo.findById(1L) } returns User(1, "Alice")

// when val result = service.getUserName(1L)

// then assertEquals("Alice", result) coVerify(exactly = 1) { repo.findById(1L) } }

@Test fun `should return Unknown when user not found`() = runTest { // given coEvery { repo.findById(any()) } returns null

// when val result = service.getUserName(99L)

// then assertEquals("Unknown", result) }}

النقاط الرئيسية:

  • coEvery و coVerify — للعمل مع الدوال من نوع suspend.
  • mockk() ينشئ كائنًا وهميًا فارغًا، spyk() — كائنًا وهميًا جزئيًا لكائن حقيقي.
  • استخدم slots لالتقاط الوسائط.


1.2. اختبار lambdas و extension-functions

يسمح MockK بإنشاء كائنات وهمية لدوال الامتداد، وهو أمر بالغ الأهمية لأطر العمل مثل Ktor أو Spring WebFlux:

class StringValidator {    fun String.isValidEmail(): Boolean = this.contains("@")}

// اختبار@Testfun `test extension mock`() { val validator = mockk<StringValidator>() with(validator) { every { "test@mail.com".isValidEmail() } returns true every { "invalid".isValidEmail() } returns false } assertTrue("test@mail.com".isValidEmail()) assertFalse("invalid".isValidEmail())}


2. اختبار التكامل: قاعدة البيانات و Testcontainers

تتحقق اختبارات التكامل من كيفية تفاعل كودك مع التبعيات الحقيقية: قواعد البيانات، قوائم انتظار الرسائل، واجهات API الخارجية. هنا تأتي Testcontainers للمساعدة — وهي مكتبة تقوم بتشغيل حاويات Docker مباشرة أثناء الاختبارات.



2.1. إعداد Testcontainers مع PostgreSQL

لتطبيق Spring Boot، يبدو الأمر كما يلي:

المدونات

توصيات الكتب