اختبار ETL وخطوط أنابيب البيانات
الاستخراج والتحويل والتحميل (ETL: Extract, Transform, Load) عملية تقرأ فيها مهمةٌ البيانات من أنظمة المصدر، وتعيد تشكيلها وفق قواعد العمل، ثم تكتبها في هدف مثل مستودع البيانات (Data Warehouse). ويتحقق اختبار ETL من أن كل صف يجب أن يصل قد وصل مرة واحدة بالضبط، وأن كل قيمة حُوّلت كما تنص القواعد. مثال: كل ليلة تنسخ مهمةٌ طلبات الأمس من قاعدة طلبات متجر إلى مستودع المبيعات، فتحوّل المبالغ إلى الريال، وتربط رموز الحالة بأسمائها، وتتجاوز متاجر الاختبار؛ ولوحة المعلومات المالية لا تقرأ إلا من المستودع.
تصبح استعلامات العدّ والجمع والصفوف اليتيمة والتكرارات من دليل SQL للمختبِرين فحوصَ المهمة، والمقارنة قبل وبعد التي استخدمتها في الترحيل تُجرى الآن مع كل تحميل. والفرق التي تحمّل أولاً ثم تحوّل داخل الهدف (ELT) تستخدم الفحوص نفسها.
لماذا يهم
عيوب خطوط الأنابيب صامتة. فالمهمة التي تُسقط بضعة صفوف، أو تحمّل دفعة (Batch) مرتين، أو تقرّب المبالغ إلى الأسفل، تنتهي مع ذلك بالحالة «success»، ولا يرى أي مستخدم رسالة خطأ. ويظهر الضرر لاحقاً أرقاماً خاطئة في التقارير والفواتير، بعد أن تكون قرارات قد اتُّخذت بناءً عليها.
وغالباً لا توجد واجهة مستخدم: فالمخرجات آلاف الصفوف، والنتيجة المتوقعة تأتي من وثيقة الربط ومن الحساب. وإثبات أن مجموعتي بيانات متفقتان، إثباتاً يعمل تلقائياً، مهارة ستعيد استخدامها في التكامل والترحيل والتحليلات.
الاستخراج والتحويل والتحميل: ماذا تفحص في كل مرحلة
افحص كل مرحلة عند حدودها. وأساس الاختبار عادةً وثيقة الربط من المصدر إلى الهدف (Source-to-Target Mapping): تذكر لكل عمود في الهدف أعمدة المصدر وقاعدة التحويل وما يحدث للقيم غير الصالحة. وإن لم توجد هذه الوثيقة، فكتابتها مع المطور غالباً أنفع نشاط اختبار تقوم به.
- الاستخراج: تصل كل صفوف النافذة المتفق عليها (مثل الأمس من الساعة 00:00 بتوقيت الرياض حتى الساعة 00:00 من اليوم دون تضمينها؛ فالمرشِّح الذي ينتهي عند 23:59:59 يُسقط صفاً طابعه الزمني 23:59:59.5)، ويطابق العدد ما يعلنه المصدر، ويحتفظ النص العربي أو الهندي بترميزه. وفي ملفات CSV، ينص RFC 4180 على أن الحقل الذي يحتوي على فاصلة أو علامة اقتباس مزدوجة أو سطر جديد ينبغي أن يوضع بين علامتي اقتباس مزدوجتين، وأن تُضاعَف كل علامة اقتباس بداخله؛ والقارئ الذي يقسم السطر عند الفواصل فحسب يزيح الأعمدة التي بعدها.
- التحويل: كل قاعدة ربط تعطي القيمة المتوقعة، حتى مع قيم NULL والرموز المجهولة والقيم الحدّية؛ والصفوف التي تخالف قاعدة تذهب إلى جدول المرفوضات مع سببها، والصفوف التي تستبعدها قاعدة تُحصى.
- التحميل: تصل الصفوف إلى الجدول الصحيح، وتبقى مفاتيح العمل (Business Keys) فريدة، وهي المفاتيح الطبيعية القادمة من المصدر مثل
order_id، وتحميل الدفعة نفسها مرتين يترك الهدف دون تغيير: أي أن تكرار التحميل لا يترك أثراً إضافياً (Idempotent).
المطابقة: حساب كل صف
المطابقة (Reconciliation) تقارن المصدر بالهدف وتفسّر كل فرق بينهما. يحق لخط الأنابيب أن يحمّل صفوفاً أقل مما قرأ، لأن القواعد تستبعد بعضها والتحقق يرفض بعضها، لكن كل صف يجب أن ينتهي في مكان واحد بالضبط: صفوف المصدر = المحمّلة + المرفوضة + المستبعدة. وإن لم تتوازن المعادلة، فقد ضاعت صفوف أو تكررت.
- 1الاستخراجكل صفوف النافذة المتفق عليها؛ والعدد والأعمدة والترميز كما يعلنها المصدر
فرع: فشل فحص المخطط أو الملف ← إيقاف التشغيلفشل
- 2التحقق من الصفوفالحقول الإلزامية والأنواع والقيم المسموحة
فرع: الصفوف المعيبة ← جدول المرفوضات مع رمز السببفشل
- 3التحويلقواعد الربط: جداول البحث والتحويلات والمناطق الزمنية والقيم الافتراضية والتكرار
فرع: الصفوف التي تستبعدها قاعدة تُحصى ولا تضيع
- 4التحميلتبقى مفاتيح العمل فريدة؛ وإعادة تحميل الدفعة نفسها لا تغيّر شيئاً
- 5المطابقة وفحوص الجودةتتفق الأعداد ومجاميع التحكم والمفاتيح، وتنجح فحوص الجودة
source = loaded + rejected + filteredبوابة
طوال الخطوات 1–5 جدول التدقيق: أعداد كل مرحلة في كل تشغيل
بعد ذلك:النشر إلى التقارير فقط حين يتوازن التشغيل
ترتيب توضيحي: بعض خطوط الأنابيب تتحقق داخل خطوة التحويل، أو تحمّل أولاً ثم تحوّل داخل الهدف (ELT).
افحص على ثلاثة مستويات. الأعداد لكل تشغيل ويوم وحالة تُظهر أن الإجماليات متفقة. ومجاميع التحكم (Control Totals)، مثل مجموع المبالغ، تُظهر أن القيم لم تُقتطع ولم تضِع في التقريب. والمقارنة على مستوى المفاتيح، أي استعلام LEFT JOIN … IS NULL من دليل SQL للمختبِرين مُشغَّلاً في الاتجاهين، تسمّي المعرّفات الناقصة أو الزائدة بعينها، وهذا ما يحتاجه المطور. وبين نظامين مختلفين، صدّر المفاتيح من الطرفين وقارنها في مكان واحد.
-- Balance one run (src_orders = the extracted rows, as staged)
SELECT
(SELECT COUNT(*) FROM src_orders
WHERE order_date = '2026-09-30') AS source_rows,
(SELECT COUNT(*) FROM fact_sales
WHERE order_date = '2026-09-30') AS loaded,
(SELECT COUNT(*) FROM reject_orders
WHERE order_date = '2026-09-30') AS rejected,
(SELECT COUNT(*) FROM src_orders
WHERE order_date = '2026-09-30'
AND store_type = 'TEST') AS filtered;
-- Source orders that reached neither the target nor the reject table
SELECT s.order_id
FROM src_orders s
LEFT JOIN fact_sales f ON f.order_id = s.order_id
LEFT JOIN reject_orders r ON r.order_id = s.order_id
WHERE s.order_date = '2026-09-30'
AND COALESCE(s.store_type, '') <> 'TEST' -- NULL store_type must not hide a row
AND f.order_id IS NULL
AND r.order_id IS NULL;
-- The other direction: target rows with no source order
SELECT f.order_id
FROM fact_sales f
LEFT JOIN src_orders s ON s.order_id = f.order_id
WHERE f.order_date = '2026-09-30'
AND s.order_id IS NULL;جرّبها: محوّل CSV إلى SQL جرّبها: مدقّق استعلامات SQL جرّبها: مقارنة النصوص (Diff)
اختبار قواعد التحويل
كل صف في وثيقة الربط شرطُ اختبار (Test Condition). صمّم صفوف الإدخال بتقسيم التكافؤ وتحليل القيم الحدّية وجداول القرار، وضعها في مجموعة بيانات مصدر صغيرة تعرف فيها كل قيمة متوقعة، ثم شغّل المهمة وقارن الهدف صفاً صفاً. أما التشغيل الكبير الشبيه ببيئة الإنتاج فيضيف الحجم والقيم المفاجئة؛ وأنت تحتاج إلى الاثنين.
- جداول البحث: الحالة
P←Paid؛ واختبر أيضاً رمزاً مجهولاً والحرف الصغيرp. - التحويلات: المبلغ × سعر الصرف في تاريخ الطلب، مقرّباً إلى منزلتين عشريتين. اختبر نتيجة تقع في المنتصف تماماً مثل 10.125: تقريب النصف إلى الأعلى (Half-Up) يعطي 10.13، وتقريب النصف إلى الرقم الزوجي (Half-to-Even) يعطي 10.12. واختبر أيضاً سعراً مفقوداً.
- المناطق الزمنية: التحويل من UTC إلى توقيت الرياض (UTC+3) ينقل الطلبات من الساعة 21:00 UTC فصاعداً إلى اليوم التالي؛ فاختبر 20:59:59 و21:00:00 UTC.
- التكرار وقيم NULL: حين يرسل المصدر الطلب نفسه مرتين، تحدد القاعدة أي النسختين تُعتمد، مثل صاحبة أحدث
updated_at؛ وقد يصبح الخصم الذي قيمته NULL صفراً.
جرّبها: مولّد مجموعات الأرقام العشرية جرّبها: مولّد بيانات اختبار التواريخ
فحوص جودة البيانات والتحقق في الخلفية
المطابقة تثبت أن شيئاً لم يضِع، وفحوص جودة البيانات تثبت أن ما وصل صالح للاستخدام. تختلف أسماء الأبعاد من فريق لآخر، لكن معظم الفرق تفحص الأبعاد التالية، كل منها باستعلام تعني نتيجته الفارغة النجاح.
التحقق من البيانات في الخلفية (Backend Data Validation) يعني أن خط الأنابيب نفسه يشغّل هذه الفحوص في كل تشغيل: فحص المخطط عند الوصول، وقواعد للصفوف ترسل الصفوف المعيبة إلى جدول المرفوضات مع رمز السبب، وحدود يُتفق عليها مع مالك البيانات توقف التشغيل قبل النشر، وجدول تدقيق بأعداد كل تشغيل. واختبر هذه الآلية أيضاً: أدخل صفاً يخالف كل قاعدة، وارفع نسبة المرفوضات فوق الحد لتتأكد من أن التشغيل يتوقف وأن أحداً يُنبَّه.
- الاكتمال (Completeness): لكل عملية بيع متجر ومبلغ.
- التفرّد (Uniqueness): صف واحد لكل مفتاح عمل، مثل
order_id. - الصلاحية (Validity): رموز حالة معروفة، ومبلغ أكبر من صفر، ولا تواريخ في المستقبل.
- الاتساق (Consistency): كل عملية بيع تشير إلى متجر موجود، ومجموع الأسطر يساوي إجمالي الطلب.
- الحداثة (Timeliness): انتهى التحميل في موعده، وأحدث صف من اليوم المتوقع.
- الدقة (Accuracy): عيّنة من صفوف الهدف تطابق المصدر أو تقريراً موثوقاً، حقلاً حقلاً.
مثال تطبيقي: تحميل ليلي جرى مرتين
يقرأ تشغيل 30 سبتمبر 10,000 طلب. تستبعد وثيقة الربط 120 طلباً من متاجر الاختبار، ويرفض التحقق 15 طلباً بلا معرّف متجر، فيجب أن يُضاف إلى الهدف 9,865 صفاً. ويُظهر جدول التدقيق انتهاء مهلة الاتصال بالشبكة (Timeout) الساعة 02:10، ثم إعادة تشغيل تلقائية، ثم الحالة «success» الساعة 02:40.
يعدّ استعلام التوازن 10,365 صفاً محمّلاً، أي أكثر مما أرسله المصدر: 10,000 ≠ 10,365 + 15 + 120. واستعلام الطلبات الناقصة لا يعيد شيئاً. أما استعلام التكرار فيعيد 500 معرّف طلب، حُمّل كل منها مرتين، وهذا يفسّر الزيادة كلها البالغة 500 صف، ومجموع التحكم بالريال أعلى بمقدار مبالغها بالضبط. تحمّل المهمة أجزاءً من 500 صف وتسجّل كل جزء منتهٍ في جدول تقدّم. وقد ثُبّت (Commit) أحد الأجزاء دون أن يُثبَّت سجل تقدّمه، لأن الكتابتين لم تكونا في معاملة واحدة، فأدرجته إعادة التشغيل مرة ثانية.
- تقرير الخطأ: تاريخ التشغيل، وأرقام التوازن، ومعرّفات الطلبات الـ500، وإعادة التشغيل في سجل التدقيق، والسلوك المتوقع: إعادة تشغيل الدفعة لا تغيّر الهدف.
- فحوص جديدة: شغّل كل دفعة مرتين أثناء الاختبار، وأوقف المهمة قسراً بين الكتابة وسجل تقدّمها، واجعل فحص تفرّد
order_idيوقف النشر.
أخطاء شائعة
- الثقة بحالة المهمة: «success» تعني أن المهمة انتهت، لا أن البيانات كاملة أو صحيحة.
- الاكتفاء بمقارنة إجمالي عدد الصفوف: فالصف الضائع والصف المكرر يلغي أحدهما الآخر؛ أضف مجاميع التحكم والمقارنة على مستوى المفاتيح.
- عدم عدّ الصفوف المرفوضة والمستبعدة، فلا يمكن موازنة أي تشغيل، ويبدو فقدان البيانات كأنه استبعاد.
- اختبار القواعد على نسخة كبيرة من بيانات الإنتاج فقط، حيث لا يعرف أحد ما يجب أن تكون عليه كل قيمة.
- تشغيل كل دفعة مرة واحدة: فإعادة التشغيل والاستئناف بعد الفشل والسجلات المتأخرة هي المواضع التي تتكرر فيها البيانات أو تُتخطّى.
- نسخ بيانات شخصية من الإنتاج إلى بيئة اختبار دون إخفاء هوية معتمد؛ فنظام حماية البيانات الشخصية في السعودية (PDPL) ينطبق هناك أيضاً.
من منظور ضمان الجودة
ابدأ بوثيقة الربط: راجعها كما تراجع متطلباً، واسأل قبل بناء أي شيء: ماذا يحدث لقيم NULL والرموز المجهولة والتكرارات والبيانات المتأخرة وإعادة التشغيل؟ واتفق مع مالك البيانات على الفحوص التي توقف النشر، والفحوص التي تكتفي بالتحذير، ونسبة المرفوضات المقبولة.
لكل تشغيل تختبره، سجّل معرّف التشغيل ونافذة التاريخ وأرقام التوازن ومجاميع التحكم والاستعلامات، ليتمكن أي شخص من تكرار الفحص. وأتمت الفحوص التي كشفت عيوباً، وأبلغ عن الإخفاقات بالمفاتيح وبالأثر على العمل، مثل «500 طلب حُسبت مرتين في تقرير مبيعات 30 سبتمبر»، لا «عدم تطابق في البيانات».
تمرين عملي
وازن تحميل العملاء واكتشف العيوب
مهمة تحمّل العملاء من ملف مستخرج من نظام إدارة علاقات العملاء (CRM). وثيقة الربط: يُبحث عن country في جدول (SA ← Saudi Arabia، وIN ← India، وأي رمز آخر يُرفض بالسبب BAD_COUNTRY)؛ وتُحذف المسافات حول email ويُحوَّل إلى أحرف صغيرة؛ والصف الذي لا customer_id له يُرفض بالسبب NO_ID؛ والصفوف التي فيها is_test = Y تُستبعد.
وازن التشغيل أدناه، ثم اكتب كل عيب مع مفتاحه والنتيجة المتوقعة والنتيجة الفعلية.
Extract (6 rows)
customer_id email country is_test
101 "Sara@Example.com" SA N
102 " ravi@example.com" IN N
103 "test@example.com" SA Y
(none) "noid@example.com" SA N
105 "omar@example.com" XX N
106 "lina@example.com" sa N
Target dim_customer (3 rows)
customer_id email country
101 "sara@example.com" Saudi Arabia
102 " ravi@example.com" India
106 "lina@example.com" Unknown
Reject table (1 row)
customer_id reason
(none) NO_ID- استنتج الصفوف التي يجب تحميلها ورفضها واستبعادها.
- تحقق من صحة المعادلة: المصدر = المحمّلة + المرفوضة + المستبعدة.
- قارن كل صف محمّل بالقواعد، حقلاً حقلاً.
- اكتب كل عيب مع مفتاحه والقيمة المتوقعة والقيمة الفعلية.
إظهار الإجابة النموذجية
المتوقع: يُستبعد 103؛ ويُرفض الصف الذي بلا معرّف بالسبب NO_ID؛ ويُرفض 105 بالسبب BAD_COUNTRY؛ ويُحمَّل 101 و102. أما 106 ففيه sa: وفق الوثيقة كما كُتبت هو رمز آخر فيجب رفضه، إلا إذا كان البحث يتجاهل حالة الأحرف.
التوازن: في المصدر 6 صفوف، لكن المحمّلة 3 والمرفوضة 1 والمستبعدة 1، والمجموع 5. العميل 105 ليس في الهدف ولا في جدول المرفوضات: بيانات مفقودة، وهذا أخطر العيوب، لأن التشغيل يبدو ناجحاً.
عيب: بقيت في email للعميل 102 مسافة في البداية؛ والمتوقع "ravi@example.com". التحويل إلى أحرف صغيرة يعمل (101)، فحذف المسافات هو الناقص.
عيب: الدولة في 106 هي Unknown، وهي قيمة لا تُنتجها الوثيقة أبداً؛ والمتوقع رفض بالسبب BAD_COUNTRY، أو Saudi Arabia إن كان البحث يتجاهل حالة الأحرف. اسأل مالك وثيقة الربط، واسأل أين تُحصى الصفوف المستبعدة: فمن دون هذا الرقم لا يمكن موازنة أي تشغيل.
أسئلة شائعة
ما الفرق بين اختبار ETL واختبار ELT؟
في ETL تُحوَّل البيانات قبل تحميلها؛ وفي ELT تُحمَّل خاماً ثم تُحوَّل داخل الهدف، عادةً بلغة SQL. والفحوص نفسها (المطابقة وقواعد التحويل وجودة البيانات)، لكن معظمها في ELT يُشغَّل بلغة SQL داخل نظام واحد، وتفحص أيضاً الطبقة الخام.
هل أقارن كل الصفوف، أم تكفي عيّنة؟
الأعداد ومجاميع التحكم والمقارنة على مستوى المفاتيح يجب أن تغطي كل الصفوف: فهي استعلامات رخيصة، وتكشف الصفوف الضائعة أو المكررة التي تفوتها العيّنة. أما مقارنة القيم حقلاً حقلاً فيمكن أن تعتمد على عيّنة إضافة إلى مجموعتك الصغيرة المعروفة، مختارةً بحيث تمرّ على كل قاعدة وكل قيمة خطرة.
هل اختبار ETL هو نفسه اختبار قواعد البيانات؟
يستخدم المهارات نفسها (SQL والقيود والمطابقة) لكن على موضوع مختلف. فاختبار قواعد البيانات يفحص كيف يخزّن تطبيق واحد بياناته ويغيّرها؛ أما اختبار ETL فيفحص بيانات تنتقل بين الأنظمة على دفعات، حيث المخاطر الرئيسية صفوف تضيع أو تتكرر أو تُحوَّل خطأً عبر التشغيلات.
المراجع
- ISTQB Certified Tester Foundation Level (CTFL) v4.0المنهج التأسيسي لاختبار البرمجيات: مستويات الاختبار وأنواعه وتقنيات تصميم الاختبارات وإدارة الاختبار والأدوات.
- ISTQB Glossaryالتعريفات القياسية لمصطلحات الاختبار — حالة الاختبار واختبار الانحدار والخطورة والأولوية وتحليل القيم الحدّية وغيرها.
- RFC 4180: Common Format and MIME Type for Comma-Separated Values (CSV) Filesقواعد CSV الشائعة: الفاصلة كفاصل، ونهايات الأسطر CRLF، وتحويط الحقول التي تحتوي فواصل أو علامات اقتباس أو أسطر جديدة.
- Personal Data Protection Law (English translation)النظام السعودي لحماية البيانات الشخصية — ولماذا ينبغي أن تستخدم بيئات الاختبار بيانات اصطناعية بدلاً من نسخ سجلات العملاء الحقيقية.
تدرّب بأدوات متقن
ولّد ملفات CSV بأعمدة وأنواع بيانات وأعداد صفوف وفواصل مخصصة.
تحويل بيانات CSV إلى جمل CREATE TABLE وINSERT مع استنتاج أنواع الأعمدة.
فحص جمل SQL بحثاً عن مشكلات الصياغة والأقواس غير المتوازنة والسلاسل النصية غير المغلقة والأنماط الخطرة.
قارن نصّين سطراً بسطر أو كلمةً بكلمة مع إبراز الاختلافات.
ولّد مجموعات بيانات عشرية / ذات فاصلة عائمة بدقة ثابتة ومبالغ بنمط العملات وحالات تقريب حدّية.
ولّد مجموعات بيانات للتواريخ: تواريخ عشوائية ضمن نطاق، وأيام كبيسة، ونهايات الأشهر، وحدود التوقيت الصيفي، وصيغ متعددة.
للتعمّق أكثر
تقدّمك في هذا الموضوع
سجّل الدخول لتتابع تقدّمك
علّم الموضوعات مكتملة، وتابع من حيث توقفت، وافتح امتحانات التخصص.