مقدمة: لماذا اختبار Kotlin هو قوة خارقة وليس واجبًا مملًا
\n\nتخيل: لقد كتبت تطبيقًا بلغة Kotlin. إنه يعمل. أنت سعيد. ولكن يمر أسبوع، وتضيف ميزة جديدة — وفجأة تتعطل الميزة القديمة. هل هذا مألوف؟ إذا لم يكن كذلك — فأنت إما عبقري أو لم تكتب كودًا بدون اختبارات أبدًا. اختبار Kotlin ليس مجرد علامة في قائمة مهام المطور. إنه "درعك" الشخصي ضد الأخطاء، وطريقة للنوم بهدوء بعد النشر، وأداة تجعل الكود أنظف وأكثر وضوحًا.
\n\nفي هذه المقالة، سأوضح من أين يبدأ المبتدئ في اختبار Kotlin. سنستعرض أمثلة حقيقية، ومكتبات شائعة، وحيلًا ستوفر لك ساعات من التصحيح. ستتعلم كيفية كتابة اختبارات الوحدة، وإنشاء الكائنات الوهمية (mocks)، واختبار الكوروتينات. هيا بنا!
\n\nالخطوة 1: إعداد البيئة — أول 5 دقائق
\n\nقبل كتابة أول اختبار، تحتاج إلى إضافة التبعيات. إذا كنت تستخدم Gradle (وعلى الأرجح تستخدمه)، أضف الأسطر التالية إلى build.gradle.kts:
// build.gradle.kts\ndependencies {\n // JUnit 5 — أساس اختبارات الوحدة\n testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")\n \n // MockK — أفضل مكتبة للكائنات الوهمية في Kotlin\n testImplementation("io.mockk:mockk:1.13.8")\n \n // AssertJ — تأكيدات جميلة وقابلة للقراءة\n testImplementation("org.assertj:assertj-core:3.24.2")\n \n // لاختبار الكوروتينات\n testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")\n}\n\ntasks.test {\n useJUnitPlatform()\n}\n\nتم! الآن لديك كل ما تحتاجه لكتابة الاختبارات. لاحظ: نحن نستخدم JUnit 5 (وليس 4) — وهو المعيار الحديث الذي يتوافق بشكل ممتاز مع Kotlin. تم اختيار MockK لسبب وجيه: فهو يفهم null-safety، ودوال extension، وميزات Kotlin الأخرى التي يتعامل معها Mockito بشكل سيء.
\n\nالخطوة 2: أول اختبار وحدة لك في Kotlin
\n\nلنكتب فئة بسيطة ونختبرها. لنفترض أن لدينا آلة حاسبة للخصومات:
\n\n// DiscountCalculator.kt\nclass DiscountCalculator {\n fun calculateDiscount(price: Double, discountPercent: Int): Double {\n require(price >= 0) { "السعر لا يمكن أن يكون سالبًا" }\n require(discountPercent in 0..100) { "الخصم يجب أن يكون بين 0 و 100" }\n return price * (100 - discountPercent) / 100.0\n }\n}\n\nالآن لنكتب الاختبار. أنشئ ملفًا باسم DiscountCalculatorTest.kt في مجلد src/test/kotlin:
import org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.assertThrows\nimport org.assertj.core.api.Assertions.assertThat\n\nclass DiscountCalculatorTest {\n \n private val calculator = DiscountCalculator()\n \n @Test\n fun `يجب حساب الخصم بنسبة 20% بشكل صحيح`() {\n val result = calculator.calculateDiscount(1000.0, 20)\n assertThat(result).isEqualTo(800.0)\n }\n \n @Test\n fun `يجب رمي استثناء عند سعر سالب`() {\n assertThrows<IllegalArgumentException> {\n calculator.calculateDiscount(-100.0, 10)\n }\n }\n \n @Test\n fun `يجب إرجاع السعر الكامل عند خصم 0%`() {\n val result = calculator.calculateDiscount(500.0, 0)\n assertThat(result).isEqualTo(500.0)\n }\n}\n\nلاحظ الأسلوب: نستخدم علامات التنصيص المقلوبة لأسماء الاختبارات بالعربية (Kotlin يسمح بذلك). هذا يجعل الاختبارات قابلة للقراءة حتى لزملاء العمل غير التقنيين. AssertJ يوفر واجهة fluent: assertThat(result).isEqualTo(800.0) — تُقرأ كجملة إنجليزية.
الخطوة 3: الكائنات الوهمية مع MockK — عند اختبار التبعيات
\n\nفي التطبيقات الحقيقية، نادرًا ما تعيش الفئات بمفردها. إنها تتصل بقواعد البيانات، أو APIs، أو خدمات أخرى. لتجنب الاعتماد على الأنظمة الخارجية، نستخدم الكائنات الوهمية (mocks). لنفترض أن لدينا خدمة