اختبار في Kotlin: الوحدة، التكامل، E2E من الألف إلى الياء

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

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

ابدأ الدورة

اختبار في Kotlin: الوحدة، التكامل، E2E من الألف إلى الياء

\n\n

التطوير الحديث في Kotlin يتطلب نهجًا منهجيًا للاختبار. بغض النظر عما إذا كنت تكتب الواجهة الخلفية على Ktor أو تطبيق جوال لنظام Android، فإن التغطية الجيدة للكود بالاختبارات هي ضمان لاستقرار المشروع وقابليته للتنبؤ. في هذه المقالة، سنتناول ثلاثة مستويات من الاختبار: اختبارات الوحدة (unit)، واختبارات التكامل (integration)، والاختبارات الشاملة (e2e). ستتعرف على الأدوات التي يجب استخدامها، وكيفية كتابة اختبارات فعالة في Kotlin وتجنب الأخطاء الشائعة.

\n\n

1. اختبار الوحدة في Kotlin: الأساس

\n\n

تتحقق اختبارات الوحدة من عمل الدوال أو الفئات أو الطرق الفردية بمعزل عن التبعيات الخارجية. في Kotlin، يُستخدم إطار العمل JUnit 5 غالبًا مع مكتبة المحاكاة MockK.

\n\n

إعداد المشروع

\n\n

أضف التبعيات في ملف build.gradle.kts:

\n\n
dependencies {\n    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")\n    testImplementation("io.mockk:mockk:1.13.8")\n}\n
\n\n

مثال على اختبار وحدة

\n\n

لنفترض أن لدينا خدمة بسيطة لحساب الخصم:

\n\n
class DiscountService {\n    fun applyDiscount(price: Double, discountPercent: Int): Double {\n        require(discountPercent in 0..100) { "يجب أن تكون نسبة الخصم بين 0 و 100" }\n        return price * (100 - discountPercent) / 100\n    }\n}\n
\n\n

اختبار هذه الخدمة:

\n\n
import org.junit.jupiter.api.Assertions.*\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.assertThrows\n\nclass DiscountServiceTest {\n\n    private val service = DiscountService()\n\n    @Test\n    fun `applyDiscount يحسب خصم 50 بالمئة بشكل صحيح`() {\n        val result = service.applyDiscount(1000.0, 50)\n        assertEquals(500.0, result, 0.001)\n    }\n\n    @Test\n    fun `applyDiscount يرمي استثناء عند نسبة خصم غير صحيحة`() {\n        assertThrows<IllegalArgumentException> {\n            service.applyDiscount(100.0, 150)\n        }\n    }\n}\n
\n\n

نصيحة: استخدم assertThrows للتحقق من الاستثناءات وقم بتسمية الاختبارات بسلاسل نصية واضحة - فهذا يحسن قابلية قراءة التقارير.

\n\n

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

\n\n

عندما تعتمد فصلك على مكونات أخرى (مثل مستودع أو API)، استخدم المحاكاة:

\n\n
class OrderService(private val paymentGateway: PaymentGateway) {\n    fun processOrder(amount: Double): String {\n        if (paymentGateway.charge(amount)) {\n            return "تم الدفع بنجاح"\n        }\n        return "خطأ في الدفع"\n    }\n}\n\n// اختبار\n@Test\nfun `processOrder يعيد النجاح عند الدفع الناجح`() {\n    val mockGateway = mockk<PaymentGateway>()\n    every { mockGateway.charge(any()) } returns true\n\n    val service = OrderService(mockGateway)\n    val result = service.processOrder(500.0)\n\n    assertEquals("تم الدفع بنجاح", result)\n    verify { mockGateway.charge(500.0) }\n}\n
\n\n

2. اختبار التكامل: التحقق من تفاعل المكونات

\n\n

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

\n\n

مثال مع قاعدة بيانات PostgreSQL

\n\n

أضف التبعيات:

\n\n
testImplementation("org.testcontainers:testcontainers:1.19.3")\ntestImplementation("org.testcontainers:postgresql:1.19.3")\n
\n\n

لنكتب اختبارًا لطبقة DAO:

\n\n
class UserRepositoryIntegrationTest {\n\n    companion object {\n        private val postgres = PostgreSQLContainer<Nothing>("postgres:15").apply {\n            withDatabaseName("testdb")\n            withUsername("test")\n            withPassword("test")\n            start()\n                

المدونات

توصيات الكتب