أفضل الممارسات لاختبار تطبيقات Serverless بكفاءة


تُعدّ Serverless أكثر من مجرد نموذج لتنفيذ الحوسبة السحابية؛ إنها تُغيّر طريقة تخطيطنا وبنائنا ونشرنا للتطبيقات. ولكنها تُغيّر أيضًا طريقة اختبار تطبيقاتنا.

تعرّف على أليكس. أليكس مطور JavaScript عادي، يركز على Node.js في الآونة الأخيرة.

صورة توضيحية للمقال

هذا هو أليكس.

على مدار الشهرين الماضيين، كان صديقاه المقربان، آنا وجيف، يتحدثان دائمًا عن مفهوم Serverless. ورغم أنهما مزعجان من وقت لآخر، إلا أنه يحب فكرة تطبيقات Serverless. حتى أنه قام بنشر بعض الدوال البسيطة على AWS Lambda و Azure في مرحلة ما.

صورة توضيحية للمقال

آنا وجيف يتحدثان دائمًا عن مفهوم Serverless.

في مرحلة ما، حصل أليكس وفريقه على مشروع جديد. وبعد بعض التحليلات، اعتقد أليكس أنه سيكون مناسبًا تمامًا لـ Serverless. عرض الفكرة على فريقه. كان بعض أعضاء الفريق متحمسين، ولم يعجب أحدهم الفكرة، لكن معظمهم لم يكن لديهم رأي قوي. لذلك، قرروا تجربتها — لم يكن المشروع كبيرًا جدًا، وكانت المخاطر منخفضة.

صورة توضيحية للمقال

فريق أليكس يناقش استخدام Serverless في مشروعهم الجديد.

قرأ الفريق عن Serverless، وتكونت لديهم فكرة عن كيفية هيكلة تطبيقهم الجديد. لكن لم يكن أحد متأكدًا من كيفية دمج Serverless في عملية التطوير المعتادة لديهم. في تلك اللحظة، كانت عمليتهم تبدو كالتالي:

  • يحللون ميزة جديدة.
  • للميزات الأقل تعقيدًا، يبدأون بالكود، ثم يقومون بتشغيله محليًا ويضيفون بعض الاختبارات في النهاية.
  • للميزات الأكثر تعقيدًا، يتبعون نسختهم الخاصة من TDD: يبدأون بالاختبارات، ثم يكتبون الكود، ويختبرونه محليًا.
  • عندما تكون الميزة جاهزة، تنتقل إلى أداة CI التي تنشرها في بيئة الاختبار.
  • ثم يتولى فريق QA الميزة الجديدة لجولة أخرى من الاختبار اليدوي.
  • إذا كان كل شيء يبدو جيدًا، ينتقل التطبيق عبر CI إلى الإنتاج.
صورة توضيحية للمقال

عملية التطوير المعتادة لفريق أليكس.

قرروا البدء خطوة بخطوة، ثم حل المشكلات عند مواجهتها. اختاروا ميزة صغيرة، وبما أنها كانت بسيطة، بدأوا بالكود. عندما كان جزء البرمجة جاهزًا، واجهوا أول عقبة: كيف يمكنك تشغيل تطبيقات Serverless محليًا؟

الاختبار المحلي (Local Testing)

مع تطبيقات Serverless، لا تدير البنية التحتية. يبدو هذا رائعًا، ولكن كيف يمكنك بعد ذلك تشغيل تطبيقك محليًا؟ هل يمكنك فعل ذلك من الأساس؟

صورة توضيحية للمقال

العقبة الأولى: كيف يمكنك تشغيل تطبيق Serverless محليًا؟

اعتمادًا على تطبيقك ومزود Serverless، يمكنك تشغيل بعض أجزاء تطبيقك محليًا. للقيام بذلك، يمكنك استخدام بعض الأدوات والتقنيات التالية:

  • Azure Functions Core Tools (لدوال Azure)
  • AWS SAM CLI (لتطبيقات AWS Lambda المبنية باستخدام AWS SAM)
  • أدوات الطرف الثالث (مثل: localstack)
  • docker-lambda لمحاكاة AWS Lambda المحلية
  • تشغيل دالة Node.js محليًا

بالطبع، القائمة ليست كاملة — هناك المزيد من الأدوات، ونرى أدوات جديدة تظهر كل يوم تقريبًا الآن. معظم هذه الأدوات لديها قيود معينة. يمكنها محاكاة دوال Serverless وعدد قليل من الخدمات الأخرى، مثل API Gateway. ولكن ماذا عن الأذونات (permissions)، وطبقة المصادقة (auth layer)، والخدمات الأخرى؟

يساعد الاختبار المحلي في التحققات السريعة للتأكد من أن دالتك تعمل. ولكن هل هناك طريقة أفضل للتأكد من أن تطبيق Serverless الخاص بك يعمل كما هو متوقع؟ نعم، هناك. الخطوة الأولى والأكثر أهمية هي: كتابة الاختبارات.

لذلك، جرب أليكس وفريقه دالتهم الأولى محليًا، وبما أنها بدت تعمل، انتقلوا إلى الخطوة التالية.

الاختبارات الآلية (Automated Tests)

لقد تحول أليكس وفريقه للتو إلى Jest لاختبار تطبيقات Node.js الخاصة بهم. لا يزالون يقومون بالكثير من أعمال الواجهة الأمامية (front end)، لذلك يرغبون في استخدام نفس الأدوات للمكدس الكامل (full stack) كلما أمكن ذلك. هل يمكنهم استخدام Jest لاختبار تطبيقات Serverless أيضًا؟ وماذا يجب عليهم اختباره؟

صورة توضيحية للمقال

العقبة الثانية: كيف تؤثر Serverless على الاختبارات الآلية؟

بعد تحقيق سريع، أدركوا أنه يمكنهم استخدام أدوات اختبار Node.js المفضلة لديهم. تعمل Jest و Jasmine و Mocha وغيرها بشكل جيد مع Serverless.

ماذا يجب أن تختبر في تطبيق Serverless؟

مع تطبيقات Node.js الخاصة بهم، يتبع أليكس وفريقه هرم أتمتة الاختبار ثلاثي المستويات. تم ذكر هرم الاختبار لأول مرة بواسطة مايك كوهن (Mike Cohn) في كتابه “Succeeding with Agile”. كما يحدد هرم الاختبار، لديهم:

  • الكثير من اختبارات الوحدة (unit tests)، لأنها الأقل تكلفة (الأسرع في الكتابة والتشغيل).
  • عدد أقل من اختبارات التكامل (integration tests)، لأنها أكثر تكلفة، وتستغرق وقتًا أطول للتشغيل.
  • عدد قليل من اختبارات واجهة المستخدم (UI tests)، لأنها الأكثر تكلفة (تتطلب بعض أدوات GUI) والأبطأ في التشغيل.

بالإضافة إلى ذلك، لديهم أيضًا اختبار يدوي قائم على الجلسات (manual session-based testing)، يقوم به فريق QA الخاص بهم.

صورة توضيحية للمقال

هرم الاختبار مع الاختبار اليدوي.

كيف تؤثر Serverless على هرم أتمتة الاختبار؟

تعتمد الإجابة على المستوى. لكن هرم الاختبار يبدو أقل شبهاً بالأهرامات المصرية، وأكثر شبهاً بأهرامات المايا.

  • طبقة اختبارات الوحدة (Unit tests) لا تتأثر كثيرًا. لا تزال اختبارات الوحدة هي الأقل تكلفة في الكتابة والتشغيل، ولكن الوحدات يمكن أن تكون أصغر.
  • طبقة اختبارات التكامل (Integration tests) تصبح أكثر أهمية من أي وقت مضى، لأن تطبيقات Serverless تعتمد بشكل كبير على عمليات التكامل. كما أنها أرخص، لأن امتلاك قاعدة بيانات Serverless للاختبار فقط أمر غير مكلف. لذلك، في "هرم اختبار Serverless" تحتاج إلى المزيد من اختبارات التكامل.
  • طبقة اختبارات واجهة المستخدم الرسومية (GUI tests) هي أيضًا أرخص وأسرع، بسبب التوازي الأقل تكلفة.
  • طبقة الاختبار اليدوي (Manual testing) تبقى كما هي. لكن Serverless يمكن أن تساعدك على تحسينها قليلاً. سنتعمق في التفاصيل حول ذلك لاحقًا.
صورة توضيحية للمقال

هرم اختبار Serverless.

أخيرًا، كان لدى أليكس وفريقه فكرة عن مكان التركيز. كانت المشكلة التالية هي كيفية كتابة دالة لاختبارها بسهولة أكبر.

كيفية كتابة دوال Serverless قابلة للاختبار

تحتاج إلى التفكير في المخاطر التالية أثناء كتابة دالة Serverless:

  • مخاطر التكوين (Configuration risks): هل قاعدة البيانات والجدول صحيحان؟ أو هل لديك حقوق الوصول؟
  • مخاطر سير العمل التقني (Technical workflow risks): هل تقوم بتحليل واستخدام الطلب الوارد كما ينبغي؟ أو هل تتعامل مع الاستجابات الناجحة والأخطاء بشكل صحيح؟
  • مخاطر منطق الأعمال (Business logic risks): هل اتبعت جميع قواعد منطق الأعمال التي يمتلكها تطبيقك؟
  • مخاطر التكامل (Integration risks): هل تقرأ بنية الطلب الوارد بشكل صحيح؟ أو هل تخزن الطلب في قاعدة البيانات بشكل صحيح؟

للتأكد من أن دالة Serverless الخاصة بك تعمل بشكل صحيح، تحتاج إلى اختبار كل هذه المخاطر. يمكنك اختبار كل منها كما فعلت لاختبارات التكامل. لكن إعداد وتكوين الخدمة في كل مرة تريد فيها اختبار أحد هذه المخاطر ليس مثاليًا.

كما يصف الخبراء:

تخيل لو أن اختبار السيارات تم بهذه الطريقة. هذا يعني أنه في كل مرة تريد فيها اختبار برغي واحد أو حتى مرآة في سيارة، سيتعين عليك تجميع السيارة بأكملها ثم تفكيكها.

لجعل التطبيق أكثر قابلية للاختبار، الحل الواضح هو تقسيم دالتك إلى عدة دوال أصغر. إحدى الطرق الرائعة للقيام بذلك هي تطبيق Hexagonal Architecture على دوال Serverless الخاصة بك.

Hexagonal Architecture، أو Ports and Adapters، هو شكل من أشكال بنية التطبيق التي تعزز فصل الاهتمامات (separation of concerns) من خلال طبقات المسؤولية. كما يوضح مبتكرها:

السماح للتطبيق بأن يتم تشغيله على قدم المساواة من قبل المستخدمين أو البرامج أو الاختبارات الآلية أو البرامج النصية الدفعية، وأن يتم تطويره واختباره بمعزل عن أجهزة التشغيل وقواعد البيانات النهائية.

إذًا، كيف ينطبق ذلك على دوال Serverless؟

بما أن أليكس وفريقه يستخدمون AWS، فقد انتهى بهم المطاف بهيكل مثل التالي:

  • يكشف منطق عمل الدالة (Function business logic) عن عدد قليل من "المنافذ" (ports) (أو يتوقع عددًا قليلًا من الوسائط). على سبيل المثال، منفذ لحدث وارد، وآخر للتخزين الدائم، وآخر للإشعارات.
  • لديهم محولان (adapters) للحدث الذي يشغل الدالة، أحدهما لمشغل AWS Lambda الحقيقي والآخر للاختبار المحلي.
  • لديهم عدة محولات للتخزين الدائم والإشعارات. على سبيل المثال، محول جدول DynamoDB ومحول في الذاكرة (in-memory adapter).
صورة توضيحية للمقال

بنية Hexagonal Architecture لدالة AWS Lambda.

كان أليكس وفريقه سعداء بأنهم يتقدمون. ولكن قبل أن ننتقل، دعنا نرى كيف تؤثر Hexagonal Architecture على كل طبقة من هرم الاختبار.

اختبار الوحدة (Unit Testing)

بقيت اختبارات الوحدة كما هي. لكن أصبح من الأسهل كتابة اختبارات الوحدة بفضل Hexagonal Architecture. يمكنهم ببساطة استخدام محول محلي (local adapter) أو محاكاة (mock) كمحول لاختبار طبقة منطق عمل الدالة بمعزل عن غيرها.

اختبار التكامل (Integration Testing)

استفادت اختبارات التكامل كثيرًا من Hexagonal Architecture. لقد تمكنوا من اختبار التكاملات التي يمتلكونها بالكامل. يتم محاكاة تكاملات الطرف الثالث (Third-party integrations) باستخدام محولات أخرى.

كيف يعمل ذلك في الممارسة العملية؟

تحتوي كل دالة من دوال Serverless الخاصة بهم على ملفي lambda.js و main.js.

  • يحتوي ملف main.js على منطق عمل دالة Serverless.
  • ملف lambda.js مسؤول عن ربط المحولات واستدعاء ملف main.js.

يحتوي ملف main.js على اختبارات الوحدة والتكامل الخاصة به. لكن اختبارات التكامل الخاصة به لا تختبر التكامل الكامل مع الخدمات النهائية، مثل AWS S3، لأن ذلك سيبطئها. بدلاً من ذلك، يستخدمون محولًا في الذاكرة (in-memory adapter) لاختبار الدالة مع تكامل تخزين الملفات.

يتم تكامل AWS S3 من خلال FileRepository، الذي يحتوي على اختبارات الوحدة والتكامل الخاصة به. تتحقق اختبارات التكامل من استخدام AWS S3 للتأكد من أن التكامل النهائي يعمل بالفعل.

على عكس main.js، لا يحتوي ملف lambda.js على اختبارات، لأنه في معظم الأحيان يحتوي على بضعة أسطر من الكود فقط.

صورة توضيحية للمقال

تمثيل مرئي لدالة AWS Lambda واحدة مع الاختبارات.

هذا النهج يشبه التقنية التي يستخدمها فريق MindMup لاختبار دوال Serverless. باستخدامه، يمكنك بسهولة اختبار تكاملات دوالك، ولا تزال تجعل اختبارات التكامل الخاصة بك أسرع.

اختبار واجهة المستخدم الرسومية (GUI Testing)

بما أن أليكس وفريقه كانوا يبنون واجهة خلفية (back end) للتطبيق، فإن طبقة اختبارات واجهة المستخدم الرسومية لم تكن ذات صلة. ولكن مع تعلمهم المزيد عن Serverless، أدركوا أنه يمكنهم استخدامها لتحسين طبقة اختبارات واجهة المستخدم (UI tests) للتطبيقات الأخرى التي كانوا يعملون عليها.

اختبارات واجهة المستخدم مكلفة وبطيئة، لأنها تعمل في المتصفح. لكن Serverless غير مكلفة وتتوسع بسرعة. إذا تمكنوا من تشغيل متصفح في AWS Lambda، فسيحصلون على توازي غير مكلف. وهذا سيجعل اختبارات واجهة المستخدم الخاصة بهم أرخص وأسرع.

ولكن، هل يمكنك تشغيل متصفح، مثل Chrome، داخل دالة Serverless؟ نعم! وهذا سهل بمساعدة أدوات مثل Serverless Chrome و Chromeless و Puppeteer.

صورة توضيحية للمقال

استخدام دوال AWS Lambda لتوازي اختبارات واجهة المستخدم (UI tests).

يمكن أن يجلب لنا مزيج من Serverless والمتصفحات الخالية من الواجهة الرسومية (headless browsers) جيلًا جديدًا من أدوات اختبار واجهة المستخدم. يمكننا بالفعل رؤية وتجربة بعضها، مثل Appraise.

التكامل المستمر / النشر المستمر (CI / CD)

عندما اختبر أليكس وفريقه دالة Serverless الأولى، حان الوقت لنشر الكود في بيئة الاختبار. وهذا أثار سؤالًا جديدًا: كيف يمكنهم استخدام أدوات CI/CD لنشر تطبيق Serverless الخاص بهم؟

صورة توضيحية للمقال

الإجابة بسيطة: يمكنهم استخدام أداة CI لتشغيل الاختبارات ونشر التطبيق. لنشر التطبيق، استخدم أي أداة شائعة، مثل Claudia.js و AWS SAM و Serverless Framework.

لا يزال بإمكانك استخدام أداة CI المفضلة لديك (مثل Jenkins أو TravisCI أو SemaphoreCI)، أو إذا كنت ترغب في الالتزام بـ AWS، يمكنك تجربة AWS CodeBuild.

الاختبار اليدوي (Manual Testing)

على الرغم من أن الاختبار اليدوي لا يتأثر بشكل مباشر بـ Serverless، فقد وجد الفريق طريقة لتحسين عملية QA الخاصة بهم.

صورة توضيحية للمقال

مراحل ونشر تطبيقات Serverless غير مكلفة وغالبًا ما تكون سريعة الإعداد. أيضًا، مع Serverless، لا تدفع مقابل التطبيق إذا لم يستخدمه أحد. هذا يعني أن امتلاك بيئة اختبار لم يكن أرخص من أي وقت مضى!

أيضًا، مع Serverless، يمكنك غالبًا ترقية الدالة من مرحلة إلى أخرى. هذا يعني أن فريق QA الخاص بك يمكنه اختبار دالة، وعندما يؤكدون أنها تعمل، يمكنك ترقية نفس الدالة إلى الإنتاج.

ما وراء الاختبار: المراقبة (Monitoring)

قام أليكس وفريقه بنشر أول دالة Serverless لهم في بيئة ما قبل الإنتاج، وكان الفريق سعيدًا لأنهم تعلموا كيفية اختبار تطبيقات Serverless.

صورة توضيحية للمقال

استمروا في استخدام Serverless في المشروع، وقدموها إلى عدد قليل من المشاريع الأخرى. انضم أليكس إلى صديقيه آنا وجيف، كواعظ ثالث، مزعج أحيانًا، لـ Serverless. وعاشوا بسعادة إلى الأبد.

صورة توضيحية للمقال

انضم عضو جديد إلى فريق وعاظ Serverless.

ولكن على الرغم من أن تطبيقهم كان مختبرًا جيدًا، حدث شيء ما بين عشية وضحاها. بعد التحقيق، اكتشفوا أن أحد التكاملات قد تغير. لقد تعلموا أن الاختبار مهم لتطبيقات Serverless، لكنه ليس كافيًا.

بما أن تطبيقات Serverless تعتمد بشكل كبير على التكاملات، فإن المخاطر تتحول من الكود الخاص بك إلى التكاملات. ولكي تتمكن من اكتشاف تغييرات التكامل والتفاعل بسرعة، يحتاج تطبيقك إلى مراقبة مناسبة.

لحسن الحظ، هناك المزيد والمزيد من أدوات مراقبة Serverless في السوق كل يوم. بعض الخيارات الجيدة والشائعة هي IOpipe و Thundra و Dashbird و Epsagon.

لكن تطبيقات Serverless غالبًا ما تحتوي على عميل سميك (thick client)، مما يعني أن مراقبة الواجهة الخلفية (back end monitoring) ليست كافية. تحتاج إلى أداة مماثلة لواجهتك الأمامية (front end). يحتوي هذا السوق على الكثير من الأدوات الرائعة أيضًا، مثل Sentry و Rollbar.

وبروح Serverless، أنشأنا تطبيقًا مفتوح المصدر لتتبع الأخطاء يسمى Desole. إنه تطبيق Serverless يمكنك تثبيته في حساب AWS الخاص بك. يمكّن المؤسسات من تتبع استثناءات وأخطاء التطبيقات دون الحاجة إلى الاختيار بين راحة البرمجيات كخدمة (software-as-a-service) وأمان الحل المستضاف ذاتيًا (self-hosted solution). يمكنك التحقق منه هنا: https://desole.io.

صورة توضيحية للمقال

Desole، تتبع الأخطاء مفتوح المصدر، متكامل بإحكام مع AWS.