إن كتابة الاختبارات ليست خياراً تكميلياً، بل حجر الأساس لأي تطبيق ناجح في 2025 لا يهم إن كان التطبيق بسيطاً أو يخدم آلاف المستخدمين يومياً؛ فكل سطر كود غير مُختبَر هو دعوة مفتوحة للأخطاء
الاختبارات تضمن أن منطق تطبيقك يعمل كما تتوقع، اليوم، وغداً، وبعد خمس سنوات من الآن فهي تساعدك على إجراء تغييرات جذرية بثقة، دون خوف من تخريب شيء آخر في التطبيق و هي أيضاً بوابة لفهم أعمق للكود الذي تكتبه، لأنها تجبرك على التفكير: “ما الذي أتوقعه بالضبط من هذه الوظيفة؟ ” وهذا ما قدمه لنا المهندس عبد العزيز تللّو في جلسة احترافية أقامها ضمن مجتمع تطوير تطبيقات الموبايل مستوفياً فيها النقاط الخاصة ب Test و Test Driven Development
أسئلة لطيفة لتحفيز الفضول قبل أن نبدأ
هل تساءلت يوماً كيف يتأكد المطور المحترف أن تطبيقه لا ينهار بعد كل تعديل بسيط؟
هل تعرف الفرق بين Unit Test, Integration Test, UI Test؟
ما هو ال Mock وهل هو يساعدنا فعلاً في كتابة اختبارات قوية؟
هل تحب كتابة كود نظيف ومنظم؟ ان تعلم الطبقات هو المفتاح (Layers)
تطرّق المهندس في البداية لشرح ال software بشكل عام وماهي طبقاته
هو نظام ديناميكي يتلقى مدخلات يعالجها حسب منطق محدد ، (Business Logic) ذات قيمة للمستخدم ثم يُنتج مخرجات , و لفهم هذا النظام بشكل أفضل، نلجأ إلى تقسيم التطبيق إلى طبقات معمارية ,هذا التقسيم يجعل الكود أكثر تنظيماً، وأسهل في الاختبار، وقابل للتوسع.
في تطبيقات Flutter نستخدم غالباً البنية التالية :
Presentation Layer (طبقة العرض):
مسؤولة عن الواجهة، ما يراه المستخدم
Application Layer (طبقة التطبيق):
تنفذ منطق التحكم وتدير الحالة باستخدام أدوات مثل Bloc أو Riverpod
Data Layer (طبقة البيانات):
مسؤولة عن الوصول إلى البيانات من مصادر خارجية مثل APIs أو قاعدة بيانات محلية.
هذا الفصل بين الطبقات لا يُسهّل فقط كتابة كود نظيف، بل يجعل من السهل اختبار كل طبقة على حدة دون الاعتماد على الطبقات الأخرى، مما يعزز من جودة البرنامج واستقراره
هل تود أن تصبح مطورًا تثق به الشركات الكبيرة؟ الاختبار هو أول الطريق :
أنواع الاختبارات في Flutter
أولًا: اختبار الوحدات – Unit Test
التعريف:
هو اختبار يُركّز على جزء صغير ومعزول من الكود، مثل دالة أو كلاس، دون الاعتماد على الواجهة أو التبعيات الخارجية,و هو حجر الأساس في جودة البرمجيات، ويُعد من أكثر أنواع الاختبارات شمولًا ودقة عندما يتعلق الأمر باختبار منطق العمل
الهدف:
التحقق من صحة منطق الأعمال (Business Logic) بشكل سريع ودقيق، والتأكد من أن الوظائف الأساسية تعمل كما هو متوقع.
مثال:
int calculateScore(int correctAnswers) {
return correctAnswers * 10;
}
void main() {
test('يحسب النقاط بشكل صحيح', () {
expect(calculateScore(3), 30);
});
}
لماذا نستخدم اختبار الوحدة ؟
1- للتأكد من أن منطق التطبيق يعمل كما يجب دون الحاجة لتشغيل كامل التطبيق
2- سهل الكتابة وسريع التنفيذ
3- يساعد في اكتشاف الأخطاء مبكرًا، خاصة أثناء تطوير الميزات الجديدة
كيف تتوزع الأدوار في اختبار الوحدة ؟

1- واجهة المستخدم UI
تتفاعل مع المستخدم وتستقبل المدخلات منه
في اختبار الوحدة، يتم تجاهل هذه الطبقة لأنها تُختبر لاحقًا في اختبارات الواجهات (Widget Tests)
لكنها تتطلب تحققًا من صحة المدخلات قبل أن ترسل للطبقات الأخرى
2- طبقة الحالة (BLoC)
تتلقى البيانات من الواجهة ت, تدير الحالة وتحدد كيفية تفاعل التطبيق بناءً على المدخلا ت
هنا يُركّز اختبار الوحدة: نختب ر أن البلوك يقوم بتحديث الحالات بشكل صحيح وفقًا للحدث المُرسل
3- الخدمة (Service)
تتواصل مع مصادر خارجية مثل API أو قاعدة البيانات , تعتبر غير مستقرة في البيئة الحقيقية لذا نقوم بعمل Mock أو Fake لتفادي النتائج غير المتوقعة
4– النموذج (Model) مسؤول عن تحويل البيانات ومعالجتها , نختبر هنا أن النموذج يقوم بتحويل البيانات بشكل صحيح
الهدف هو التأكد من أن البيانات صالحة ومفهومة لبقية طبقات التطبيق
ثانيًا: اختبار الواجهات – Widget Test
التعريف:
يُستخدم لاختبار عناصر الواجهة (Widgets) بشكل مستقل داخل بيئة اختبارية، للتأكد من أنها تعمل وتعرض البيانات وتتفاعل كما يجب.
الهدف:
ضمان أن واجهات المستخدم تستجيب بشكل صحيح للتغييرات والتفاعلات، وأنها تُظهر المحتوى كما هو متوقع.
مثال:
void main() {
testWidgets('يعرض عنوان الترحيب', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: Text('مرحبًا بك')));
expect(find.text('مرحبًا بك'), findsOneWidget);
});
}
ثالثًا: اختبار التكامل – Integration Test
التعريف:
يُستخدم لاختبار التطبيق ككل – من تشغيله وحتى التفاعل مع واجهاته وطبقات البيانات – باستخدام محاكي أو جهاز حقيقي.
الهدف:
التحقق من أن التطبيق يعمل بشكل متكامل عبر جميع طبقاته، وأن رحلة المستخدم لا تنكسر.
مثال:
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('App flow test', (tester) async {
app.main();
await tester.pumpAndSettle();
final loginField = find.byKey(Key('loginField'));
await tester.enterText(loginField, 'admin');
await tester.tap(find.byKey(Key('submitBtn')));
await tester.pumpAndSettle();
expect(find.text('Dashboard'), findsOneWidget);
});
}
نوّه المهندس لضرورة استخدام TDD&mocking
Mocking
انشاء نسخة من كائن أو خدمة حقيقية، نستخدمها أثناء الاختبار لتوفير بيانات ثابتة أو سلوك متوقع
متى نستخدمه؟
عندما نريد اختبار BLoC أو Service دون الاعتماد على شبكة الإنترنت
عندما تكون الخدمة الحقيقية بطيئة، أو قد تُرجع أخطاء غير متوقعة
ما هو التطوير القائم على الاختبارات؟TDD
هو أسلوب برمجي يقوم على كتابة الاختبارات قبل كتابة الكود الفعلي ,
نكتب أولًا ما يجب أن يفعله الكود، ثم نكتب الكود الذي يجعله ينجح في ذلك
الختام
إذا كنت تطمح لأن تصبح مطور Flutter محترف في 2025، فعليك أن تتقن Tests كما تتقن بناء الواجهات, Test هو ضمان المستقبل، وهو ما يميز المبرمج العادي عن المهندس المتمكن,اجعل Testعادة، mocking أداة، وTDD هدفًا
روابط ذات صلة
ألبوم الصور
اكتشاف المزيد من Mobile Dev Meetup
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.