مقدمة: لماذا نحتاج إلى اختبار التكامل مع Docker؟
عند تطوير التطبيقات الحديثة بلغة Kotlin، وخاصة الخدمات المصغرة، من المهم التحقق من كيفية تفاعل مكونات النظام مع بعضها البعض ومع التبعيات الخارجية (قواعد البيانات، قوائم انتظار الرسائل، التخزين المؤقت). تعمل اختبارات الوحدة على عزل الكود، لكنها لا تضمن أن التطبيق يعمل بشكل صحيح في البيئة الحقيقية.
يعمل اختبار التكامل مع Docker على حل هذه المشكلة. يتيح Docker تشغيل حاويات معزولة بالخدمات اللازمة (PostgreSQL, Redis, Kafka) مباشرة قبل بدء الاختبارات وتدميرها تلقائيًا بعد الانتهاء. وهذا يوفر:
- قابلية التكرار: يتم تشغيل الاختبارات دائمًا في نفس البيئة.
- العزل: لا تؤثر الحاويات على بيئة المطور المحلية.
- السرعة: يتم تشغيل الحاويات في ثوانٍ وليس دقائق.
في هذه المقالة، سنشرح كيفية إعداد اختبار التكامل لتطبيق Kotlin باستخدام Docker، ومكتبة Testcontainers و Docker Compose. ستحصل على أمثلة جاهزة للكود وأفضل الممارسات.
1. إعداد مشروع Kotlin لاختبارات التكامل
1.1. التبعيات في ملف build.gradle.kts
للبدء، أضف التبعيات اللازمة إلى ملف build.gradle.kts الخاص بك. سنستخدم JUnit 5 و Testcontainers وبرنامج تشغيل PostgreSQL:
dependencies { // تبعيات التطبيق الأساسية implementation("org.jetbrains.kotlin:kotlin-stdlib") implementation("org.postgresql:postgresql:42.7.1")
// الاختبارات testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") testImplementation("org.testcontainers:testcontainers:1.19.3") testImplementation("org.testcontainers:postgresql:1.19.3") testImplementation("org.testcontainers:junit-jupiter:1.19.3")}
tasks.test { useJUnitPlatform()}1.2. الهيكل الأساسي لفئة الاختبار
لنقم بإنشاء فئة بسيطة لاختبار التكامل، والتي ستقوم بتشغيل حاوية PostgreSQL:
import org.junit.jupiter.api.Testimport org.testcontainers.containers.PostgreSQLContainerimport org.testcontainers.junit.jupiter.Containerimport org.testcontainers.junit.jupiter.Testcontainersimport java.sql.DriverManager
@Testcontainersclass UserRepositoryIntegrationTest {
companion object { @Container val postgres = PostgreSQLContainer<Nothing>("postgres:15-alpine") .withDatabaseName("testdb") .withUsername("test") .withPassword("test") }
@Test fun `should connect to database and execute query`() { val jdbcUrl = postgres.jdbcUrl val username = postgres.username val password = postgres.password
val connection = DriverManager.getConnection(jdbcUrl, username, password) val statement = connection.createStatement()
statement.execute("CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name VARCHAR(100))") statement.execute("INSERT INTO users (name) VALUES ('Alice')")
val resultSet = statement.executeQuery("SELECT COUNT(*) FROM users") resultSet.next() val count = resultSet.getInt(1)
assert(count == 1) println("تم اجتياز الاختبار: تم العثور على $count من المستخدمين") }}لاحظ: التعليق التوضيحي @Testcontainers يدير دورة حياة الحاوية تلقائيًا. يتم تشغيلها قبل جميع الاختبارات في الفئة وتتوقف بعد اكتمالها.
2. الاختبار مع حاويات متعددة (Docker Compose)
في المشاريع الحقيقية، غالبًا ما تكون هناك حاجة لعدة خدمات في وقت واحد: قاعدة بيانات، Redis، Kafka. يدعم Testcontainers Docker Compose، مما يسمح بوصف البنية التحتية بأكملها في ملف واحد
```