دعونا نتعمق في شجرة السرو للاختبار الشامل
نشرت: 2022-03-10تمت رعاية هذه المقالة من قبل أصدقائنا الأعزاء في LambdaTest الذين يجعلون تجربة الاختبار عبر المتصفحات أكثر سلاسة للعديد من الأشخاص حول العالم. شكرا لك!
من الصعب تخيل تطوير البرمجيات دون الاختبار الآلي اليوم. ستضمن مجموعة متنوعة جيدة من إجراءات الاختبار المختلفة مستوى عالٍ من الجودة. كأساس للاختبار ، يمكننا استخدام عدد من اختبارات الوحدة. علاوة على ذلك ، في منتصف الهرم ، إذا جاز التعبير ، توجد اختبارات التكامل. الاختبارات الشاملة هي في القمة ، وتغطي حالات الاستخدام الأكثر أهمية. سيكون هذا النوع الثالث من الاختبارات هو محور هذه المقالة.
ومع ذلك ، فإن الاختبار الشامل له بعض المزالق التي تدعو إلى القلق:
- الاختبارات الشاملة بطيئة ، وبالتالي ، فإنها تشكل عقبة كبيرة في كل استراتيجية تكامل مستمر ونشر مستمر (CI / CD). ليس ذلك فحسب ، بل تخيل إنهاء مهمة أو ميزة أو أي تطبيق آخر - انتظار تنفيذ الاختبار يمكن أن يستنزف صبر الجميع.
- يصعب الحفاظ على مثل هذه الاختبارات الشاملة ، كما أنها معرضة للخطأ ، ومكلفة من جميع النواحي بسبب الجهد المبذول في تصحيح الأخطاء. يمكن أن تسبب عوامل مختلفة هذا. يجب أن تشعر أن اختبارك هو المساعد ، وليس عائقًا على الإطلاق.
- أكبر كابوس للمطورين هو الاختبار غير المستقر ، وهو اختبار يتم تنفيذه بنفس الطريقة ولكنه يؤدي إلى نتائج مختلفة. إنه مثل "Heisenbug" ، والذي يحدث فقط إذا لم تقم بقياس التطبيق الذي يتم اختباره - أي إذا لم تنظر إليه.
لكن لا تقلق: ليس عليك الخضوع لهذه المزالق. دعونا نلقي نظرة على كيفية منع الكثير منها . ومع ذلك ، لن أعد فقط بالقمر ولن أحققه. في هذا الدليل ، سنكتب بعض الاختبارات معًا ، والتي قمت بنشرها لك في مستودع GitHub. بهذه الطريقة ، آمل أن أوضح لك أن الاختبار النهائي يمكن أن يكون ممتعًا! هيا بنا نبدأ.
ما هي الاختبارات الشاملة؟
عند الحديث عن الاختبار الشامل (أو E2E) ، أود الإشارة إليه على أنه "يعتمد على سير العمل". تلخص العبارة الاختبار الشامل جيدًا: فهي تحاكي سير عمل المستخدم الفعلي ويجب أن تتضمن أكبر عدد ممكن من المجالات الوظيفية وأجزاء من مجموعة التكنولوجيا المستخدمة في التطبيق. في النهاية ، يتظاهر الكمبيوتر بأنه عميل ويحاول التصرف كمستخدم حقيقي. هذه الاختبارات هي الأفضل لتطبيق ضغط مستمر على نظام التطبيق بأكمله ، وبالتالي فهي إجراء رائع لضمان الجودة عند وجود مجموعة التطبيقات بأكملها.
لنتذكر ما نريد تحقيقه بكل هذا. نحن نعلم أن اختبار الواجهة الأمامية عبارة عن مجموعة من الممارسات لاختبار واجهة المستخدم لتطبيق ويب ، بما في ذلك وظائفه. من المنطقي - من خلال هذه الإجراءات ، أن نضمن أن تطبيقنا يعمل بشكل صحيح وأنه لن تؤدي أي تغييرات مستقبلية إلى كسر الكود الخاص بنا. من أجل تحقيق ذلك بكفاءة ، قد تتساءل عن مقدار الاختبار الذي تحتاجه ومقدار ذلك.
هذا هو سؤال وجيه. قد تجد إجابة واحدة محتملة في استعارة: هرم أتمتة الاختبار ، الذي قدمه لأول مرة مايك كوهن وحدده مارتن فاولر ، يوضح كيفية جعل الاختبار فعالاً . نجد اختبارات وحدة سريعة ورخيصة على أدنى مستوى هرمي ، واختبارات واجهة مستخدم تستغرق وقتًا طويلاً ومكلفة (اختبار شامل) في الأعلى.
شرح هذا ومزاياه وعيوبه سيكون كافيا لمقاله الخاص. أود التركيز على مستوى واحد. يمكن أن تؤدي الاختبارات الشاملة على وجه الخصوص إلى تحسينات كبيرة في الجودة إذا تم تحديد أولوياتها بكفاءة. عند القيام بذلك ، يمكننا وضع نظامنا باستمرار تحت الضغط والتأكد من أن الوظائف الرئيسية لتطبيقنا تعمل بشكل صحيح.
رحلتي إلى السرو
عندما بدأت في تعلم كيفية كتابة الاختبارات من طرف إلى طرف ، استخدمت Mink ، مكتبة PHP ، فوق Behat ، إطار عمل تطوير يعتمد على السيناريو (BDD). بدأت باستخدام السيلينيوم بكل مميزاته وعيوبه. نظرًا لأن فريقي بدأ العمل مع Vue.js كثيرًا ، فقد غيرنا إلى إطار عمل اختبار قائم على JavaScript لضمان التكامل والتوافق الخالي من العيوب. كان خيارنا في ذلك الوقت هو Nightwatch.js ، لذلك صممت مجموعة الاختبار الجديدة من البداية.
خلال هذا الوقت ، غالبًا ما نعثر على مشاكل التوافق . يمكنك تسميتها جحيم التبعية - ناهيك عن كل القيود التي رأيناها مع السيلينيوم ولاحقًا مع WebDriver.
- في فريقنا ، لم نتمكن من تحديد إصدار Chrome من CI الخاص بنا. لذلك إذا تم إصدار تحديثات لـ Chrome ، فإن Nightwatch.js لم يكن سريعًا بما يكفي ليكون متوافقًا ، مما تسبب في العديد من الإخفاقات في خطوط أنابيب الاختبار الخاصة بنا.
- بدأ عدد أسباب الاختبارات غير المستقرة من جانب الاختبار في الارتفاع ، حيث لم تتطابق احتمالات انتظار Nightwatch.js مع منتجنا على النحو الأمثل.
لذلك ، فكرنا في بناء مجموعة الاختبار الخاصة بنا من جديد. بعد زيارة اللامؤتمر ، اكتشفت السرو.
Cypress هو إطار اختبار شامل لا يستخدم السيلينيوم أو WebDriver. تستخدم الأداة Node.js لبدء متصفح تحت تحكم خاص. يتم إجراء الاختبارات في هذا الإطار على مستوى المتصفح ، وليس فقط على مستوى التحكم عن بعد. هذا يوفر العديد من المزايا.
باختصار ، إليك الأسباب التي دفعتني إلى اختيار إطار العمل هذا:
- قدرة تصحيح ممتازة
يمكن أن يقفز عداء اختبار Cypress إلى أي حالة من حالات التطبيق عبر اللقطات. لذلك ، يمكننا أن نرى خطأ وجميع الخطوات قبله مباشرة. بالإضافة إلى ذلك ، هناك وصول كامل إلى أدوات مطور Chrome (DevTools) ، ويتم تسجيل النقرات بالكامل. - أفضل الطرق لانتظار الإجراءات في الاختبار أو واجهة المستخدم أو الردود من واجهة برمجة التطبيقات
السرو يجلب الانتظار الضمني ، لذلك ليست هناك حاجة للفحوصات المناسبة. يمكنك أيضًا إجراء الاختبار في انتظار الرسوم المتحركة واستجابات واجهة برمجة التطبيقات. - الاختبارات مكتوبة بجافا سكريبت
هذا يخفف من منحنى التعلم لكتابة الاختبارات. عداء اختبار Cypress مفتوح المصدر ، لذا فهو يناسب إستراتيجية منتجاتنا.
ومع ذلك ، هذه المقالة هي دليل ، لذلك دعونا نتوقف عن هذه المعلومات العامة ونبدأ.
ابدء
تثبيت وبدء تشغيل السرو
لنبدأ من الصفر. في حديثي عن Cypress ، عادةً ما أبدأ بإنشاء دليل جديد عبر mkdir
، ثم تثبيت Cypress على الفور. أسهل طريقة للتثبيت موضحة في هذا الرسم:
تلميح بسيط: إذا كنت لا تريد استخدام npm ، فيمكنك تثبيت Cypress عبر Yarn:
yarn add cypress --dev
البديل هو التنزيل المباشر ، باستخدام مجلدات ZIP التي يوفرها Cypress. هذا هو! بمجرد اكتمال التثبيت ، تكون جاهزًا للبدء.
هناك طريقتان لبدء تشغيل اختبارات السرو. الأول عن طريق تشغيل Cypress في وحدة التحكم ، وتشغيل الاختبارات بدون رأس:
./node_modules/.bin/cypress run
الطريقة الثانية هي استخدام إحدى ميزات Cypress الأنيقة ، وهي عداء الاختبار المتكامل. عداء الاختبار هو واجهة مستخدم لإجراء الاختبارات. لتشغيله ، يمكنك استخدام أمر مشابه:
./node_modules/.bin/cypress open
سيفتح هذا الأمر عداء الاختبار. عندما تفتح Cypress لأول مرة ، سترى هذه الواجهة:
يوفر Cypress بعض اختبارات العينة المكتوبة مسبقًا لعرض ميزاته وإعطائك بعض نقاط البداية - وهذا هو سبب الاختبارات المتاحة. دعنا نتجاهل هؤلاء الآن ، لأننا نريد أن نكتب ما يخصنا قريبًا. ومع ذلك ، يرجى وضع منطقة "اختبارات التكامل" هذه في الاعتبار ، لأنها ستفسر الكثير من السحر الذي سيحدث لاحقًا.
الانطباع الأول عن هيكل السرو
حان الوقت الآن لفتح مشروعنا الذي تم إنشاؤه حديثًا في بيئة التطوير المتكاملة (IDE) المختارة. إذا انتقلت إلى هذا المجلد ، فسترى بنية الاختبار التالية:
smashing-example └── cypress └── fixtures └── integration └── plugins └── support └── cypress.json
لنستعرض هذه المجلدات:
-
fixtures
ستجد هنا بيانات اختبار ثابتة ، والتي لا علاقة لها بالكيانات الأخرى. لذلك ، لا يتم تخزين أي معرفات هنا ، والتي يمكن أن تتغير وفقًا للحالة المحلية. -
integration
ستجد الاختبارات الفعلية هنا. -
plugins
هنا ، يمكنك تمديد Cypress ، سواء باستخدام مكونات Cypress الإضافية الحالية أو الخاصة بك. -
support
هنا ، يمكنك تمديد السرو نفسه. أوامرك ومساعديك موجودون هنا. -
cypress.json
قم بتعديل التكوينات هنا ، بما في ذلك التكوينات الخاصة بالبيئة.
حسنًا ، أعتقد أنه يمكننا العثور على طريقنا حول Cypress الآن ، سواء كان عداء الاختبار أو الكود المصدري. لكن كيف نبدأ؟ ماذا نريد أن نختبر؟
اختر حالة اختبار
يمكن أن يصبح الاختبار الشامل النموذجي معقدًا ، خاصة إذا كان يحتوي على الكثير من الخطوات. سيستغرق التنفيذ يدويًا وقتًا طويلاً. بسبب هذا التعقيد ، يمكن أن تكون اختبارات E2E صعبة في التشغيل الآلي وبطيئة في التشغيل. نتيجة لذلك ، نحتاج إلى أن نقرر بعناية الحالات التي يجب أتمتتها.
في رأيي ، المصطلح "مستند إلى سير العمل" هو المفتاح : سنختار حالات الاختبار بناءً على قصص المستخدم النموذجية. ومع ذلك ، نظرًا لأوقات التشغيل ، لا يُنصح بتغطية كل سير عمل متاح. لذلك ، نحن بحاجة إلى طريقة لتحديد أولويات حالات الاختبار لدينا.
في فريقي ، كان لدينا عدة معايير لمشروعنا. يجب أن تكون حالة الاختبار:
- تغطية عمليات سير العمل الأكثر عمومية والأكثر استخدامًا للميزة ، مثل عمليات CRUD (يصف مصطلح "المسار السعيد" تدفقات العمل هذه جيدًا) ؛
- استخدام تحليل المخاطر ، الذي يغطي سير العمل باختبارات E2E الأكثر عرضة للخطر (أي حيث تسبب الأخطاء أكبر قدر من الضرر) ؛
- تجنب التغطية المكررة ؛
- لا تستخدم بالضرورة إذا كانت اختبارات الوحدة أكثر ملاءمة (استخدم اختبار E2E لاختبار استجابة برنامجك لخطأ ، وليس الخطأ نفسه).
ثاني أهم شيء يجب مراعاته هو اختبار سير العمل الذي تريد صراحة اختباره فقط. يجب إجراء جميع الخطوات الأخرى المطلوبة لإجراء الاختبار الخاص بك باستخدام عمليات API خارج الاختبار ، لتجنب اختبارها. بهذه الطريقة ، ستضمن الحد الأدنى من أوقات تشغيل الاختبار وستحصل على نتيجة واضحة لحالة الاختبار الخاصة بك إذا فشلت. فكر في سير العمل هذا على أنه يمكن للمستخدم النهائي: التركيز على استخدام الميزة بدلاً من التنفيذ الفني .
مثال:
إذا كنت ترغب في اختبار عملية الدفع في متجر عبر الإنترنت ، فلا تقم بتنفيذ جميع الخطوات الأخرى ، مثل إنشاء المنتجات والفئات ، على الرغم من أنك ستحتاج إليها لمعالجة عملية الدفع. استخدم ، على سبيل المثال ، API أو تفريغ قاعدة البيانات لعمل هذه الأشياء ، وقم بتكوين الاختبار فقط للسحب.
مثال: العثور على مقالاتي في مجلة Smashing
أريد أن أكتب اختبارًا لهذا الموقع ، Smashing Magazine. لا يمكنني ضمان تحديث هذا الاختبار إلى الأبد ، ولكن دعونا نأمل أن يستمر. في كلتا الحالتين ، ستتمكن من العثور على هذا المثال في مستودع GitHub.
إنشاء أول اختبار لدينا السرو
في مجلد integration
، سنبدأ بإنشاء ملف جديد. دعنا نسميها find-author.spec.js
. اللاحقة .spec
تعني "المواصفات". فيما يتعلق بالاختبار ، يشير هذا إلى التفاصيل الفنية لميزة أو تطبيق معين يجب أن يفي به تطبيقك.
لتحويل ملف JavaScript الفارغ هذا إلى منزل اختبار ، سنبدأ بإعطاء مجموعة الاختبار هيكلها. سنستخدم الطريقة التي تسمى describe
. describe()
، أو context()
، يستخدم لاحتواء وتنظيم الاختبارات. بمعنى آخر ، تعمل هذه الطريقة كإطار لاختباراتنا. وبالتالي ، سيبدو ملف الاختبار الخاص بنا كما يلي:
// find-author.spec.js describe('Find authors at smashing', () => { //... });
الخطوة التالية هي إنشاء الاختبار الفعلي. سنستخدم طريقة it
. يتم استخدام it()
أو specify()
لتمثيل الاختبار الفعلي. كما ترى ، يمكننا التقاط عدة اختبارات في ملف واحد ، مما يسمح ببعض خيارات الهيكلة الممتازة.
// find-author.spec.js describe('Find authors at smashing', () => { it('Find the author Ramona Schwering', () => { cy.log('This is our brand-new test'); }); });
تلميح صغير : إذا كنت معتادًا على Mocha ، فربما تكون قد لاحظت بعض أوجه التشابه. السرو مبني على قمة موكا ، لذا فإن الصيغة هي نفسها.
حسنًا ، لنبدأ. إذا أجرينا اختبارنا في عداء اختبار Cypress ، فسنلاحظ أن Cypress سيفتح متصفحًا لإجراء الاختبار. يظهر هذا المتصفح في لقطة الشاشة أدناه:
تهانينا! لقد كتبنا اختبارنا الأول! بالتأكيد ، لا تفعل الكثير. نحن بحاجة إلى الاستمرار. دعونا نملأ اختبارنا بالحياة.
املأ الاختبار بالحياة
ما هو أول شيء يجب فعله عند اختبار موقع ويب؟ صحيح ، نحن بحاجة لفتح الموقع. يمكننا القيام بذلك باستخدام أمر Cypress. ما هي الوصية ، قد تتساءل؟
العمل مع الأوامر
يوجد نوعان رئيسيان من التعليمات المستخدمة في اختبار E2E. النوع الأول من التعليمات ، الأوامر ، يمثل الخطوات الفردية في الاختبار. في سياق Cypress ، الأوامر هي كل ما يفعله Cypress للتفاعل مع موقع الويب الخاص بك. يمكن أن يكون هذا التفاعل أي شيء - نقرة أو التمرير لأسفل في موقع الويب أو حتى البحث عن عنصر. نتيجة لذلك ، ستكون الأوامر أحد الأشياء المهمة التي سنملأ اختبارنا بها.
لذلك ، سيكون أمرنا الأول هو الأمر الذي يجب الانتقال إلى موقع الويب - smashingmagazine.com
. هذا الأمر يسمى visit
.
باستخدامه ، سيبدو اختبارنا كما يلي:
// find-author.spec.js describe('Find authors at smashing', () => { it('Find the author Ramona Schwering', () => { cy.visit('https://www.smashingmagazine.com/'); }); });
هناك أمر واحد أستخدمه كثيرًا - وستفعل أنت أيضًا. يطلق عليه get
:
cy.get('selector');
يعيد هذا الأمر عنصرًا وفقًا لمحدده - على غرار $(…)
في jQuery. لذلك ، يمكنك استخدام هذا الأمر للعثور على الأجزاء التي تتفاعل معها. عادة ، يمكنك استخدامه لبدء سلسلة من الأوامر. لكن انتظر - ما المقصود بسلسلة الأوامر؟
كما ذكرنا في بداية هذه المقالة ، فإن جميع الاختبارات وكل ما يتناسب معها مكتوب بلغة JavaScript. يمكنك وضع الأوامر في الاختبارات (أي العبارات) في سلسلة (بمعنى آخر ، بالسلاسل). هذا يعني أنه يمكن للأوامر تمرير موضوع (أو قيمة إرجاع) لأمر إلى الأمر التالي ، كما نعلم من العديد من أطر عمل الاختبار.
حسنًا ، سنبدأ سلسلة من الأوامر باستخدام الأمر get
. لإيجاد عنصر مع get
، علينا إيجاد محدده أولاً. يعد العثور على محدد فريد أمرًا ضروريًا ، لأن Cypress ستعيد جميع العناصر المتطابقة ؛ لذلك ، ضع ذلك في الاعتبار وتجنبه إذا كان غير مقصود.
التفاعل مع العناصر
يحتوي Cypress نفسه على ميزة لمساعدتك في العثور على محددات العناصر التي تريد العمل معها. تسمى هذه الميزة بـ Selector Playground ، وهي تساعدك على اكتشاف محددات فريدة لمكون أو مشاهدة جميع العناصر المطابقة لمحدد أو سلسلة نصية. لذلك ، يمكن أن تساعدك هذه الميزة كثيرًا في هذه المهمة. لتمكينه ، ما عليك سوى النقر فوق رمز الخطوط المتقاطعة في رأس واجهة المستخدم الخاصة باختبارك ، ثم قم بالمرور فوق العنصر المطلوب:
كما هو موضح في لقطة الشاشة أعلاه ، سيعرض تلميح الأداة المحدد عند التمرير أو في هذا الشريط الصغير أسفل أيقونة التقاطع ، والتي ظهرت عند النقر فوق العنصر. في هذا الشريط ، يمكنك أيضًا معرفة عدد العناصر التي تتوافق مع المحدد المحدد - مما يضمن تفرده في حالتنا.
في بعض الأحيان ، قد لا تكون تلك المحددات التي تم إنشاؤها تلقائيًا هي التي تريد استخدامها (على سبيل المثال ، إذا كانت طويلة أو يصعب قراءتها أو لا تفي بالمعايير الأخرى). المحدِّد الذي تم إنشاؤه أدناه صعب الفهم وطويل جدًا ، في رأيي المتواضع:
في هذه الحالة ، سأعود إلى DevTools بالمتصفح للعثور على محدداتي الفريدة. قد تكون على دراية بهذه الأدوات ؛ في حالتي ، غالبًا ما أختار Chrome لهذا الغرض. ومع ذلك ، قد توفر المتصفحات الأخرى المدعومة ميزات مماثلة. تبدو العملية مشابهة لـ Selector Playground ، باستثناء أننا نستخدم ميزات DevTools في علامة التبويب "العنصر".
للتأكد من أن المحدد فريد ، أوصي بالبحث عنه في عرض كود DevTools. إذا وجدت نتيجة واحدة فقط ، فيمكنك أن تكون واثقًا من أنها فريدة من نوعها.
هل تعلم أن هناك العديد من أنواع المحددات المختلفة ؟ اعتمادًا على التنوع ، يمكن أن تبدو الاختبارات وتتصرف بشكل مختلف تمامًا. بعض الأصناف مناسبة بشكل أفضل للاختبار الشامل من غيرها. إذا كنت تريد معرفة المحددات التي يجب استخدامها للحفاظ على استقرار اختباراتك ونظافتها ، فيمكنني توجيهك إلى إحدى مقالاتي التي تتناول هذه المشكلة. يقدم مطورو Cypress أنفسهم بعض الإرشادات حول هذا الموضوع في أفضل ممارساتهم.
اختبارنا كتسلسل للأوامر
حسنًا ، عد إلى اختبارنا. في ذلك ، نريد عرض سير العمل لدينا:
"بصفتي مستخدمًا ، سأبحث عن مقالة المؤلف وأنتقل إلى موقع المؤلف عبر المنطقة المرجعية في إحدى مقالاته."
سنقوم بإعادة إنتاج الخطوات التي قد يتخذها المستخدم باستخدام الأوامر. سأقوم بلصق الاختبار النهائي أدناه مع التعليقات ، والتي ستوضح الخطوات:
// find-author.spec.js it('Find the author Ramona Schwering', () => { // Open the website cy.visit('https://www.smashingmagazine.com'); // Enter author's name in search field cy.get('#js-search-input').type('Ramona Schwering'); // Navigate to author's article cy.get('h2 > a').first().click(); // Open the author's page cy.get('.author-post__author-title').click(); });
يتعامل هذا المثال مع سير العمل الذي نريد اختباره. سيقوم Cypress بتنفيذ هذا الاختبار. فهل حان الوقت لقول "مبروك"؟ هل انتهينا أخيرًا من كتابة اختبارنا الأول؟
حسنا ، يرجى إلقاء نظرة فاحصة . سينفذه Cypress ، لكنه سيفعل فقط ما يخبرك به الاختبار ، وهو ما كتبته. إذا قمت بتشغيله في عداء الاختبار ، يمكنك معرفة ما إذا كان قد اجتاز - ولكن ليس في حالة تشغيله بدون رأس. من خلال هذا الاختبار ، نعرف فقط ما إذا كان بإمكان Cypress تشغيل أوامرنا بنجاح - وليس ما إذا كان قد انتهى بنا المطاف على موقع المؤلف. لذلك ، نحتاج إلى تعليم اختبارنا لتحديد ذلك.
العمل مع التأكيدات
يعتني النوع الثاني من العبارات بأوصاف الحالة المرغوبة لواجهة المستخدم - أي ما إذا كان يجب وجود شيء ما أو أن يكون مرئيًا أو لم يعد مرئيًا. تستند التأكيدات في Cypress إلى تأكيدات Chai و Sinon-Chai ، والتي يمكن ملاحظتها في بناء الجملة.
تذكر أننا نريد التحقق مما إذا كنا في صفحة الملف الشخصي للمؤلف - صفحتي الشخصية في هذا المثال. لذلك ، نحتاج إلى إضافة تأكيد لذلك بالضبط:
// find-author.spec.js it('Find the author Ramona Schwering', () => { // Open the website cy.visit('https://www.smashingmagazine.com'); // Enter author's name in search field cy.get('#js-search-input').type('Ramona Schwering'); // Navigate to author's article cy.get('h2 > a').first().click(); // Open the author's page cy.get('.author-post__author-title').click(); // Check if we're on the author's site cy.contains('.author__title', 'Ramona Schwering').should('be.visible'); });
حسنًا ، لقد كتبنا الآن اختبارًا له قيمة. لذا ، نعم ، تهانينا على كتابة الاختبار الأول ... حتى لو لم يكن كاملاً بعد.
لنجعل اختبارنا جميلًا
حتى لو نجحنا في كتابة أول اختبار ذي مغزى وتعلمنا المفهوم الأساسي في العملية ، فلن أدمج هذا الاختبار حتى الآن إذا تم اقتراحه في طلب سحب. تم ترك بعض الأشياء لفعلها لجعلها تتألق.
خذ وقتك
يحتوي Cypress على خيار إعادة محاولة مضمّن في كل أمر تقريبًا ، لذلك لا يتعين عليك الانتظار لمعرفة ما إذا كان العنصر موجودًا بالفعل ، على سبيل المثال. ومع ذلك ، فإن هذا ينظر فقط لمعرفة ما إذا كان العنصر موجودًا في DOM ، وليس أكثر من ذلك. لا يستطيع Cypress التنبؤ بكل شيء يفعله تطبيقك ، لذلك قد يكون هناك بعض التقلبات إذا كنت تعتمد فقط على هذا.
ماذا سيفعل المستخدم إذا أراد رؤية موقع ويب لا يزال قيد التحميل؟ من المرجح أن ينتظروا حتى تصبح بعض أجزاء الموقع مرئية (وبالتالي يتم تحميلها) ثم يتفاعلون معها. في الاختبار الذي أجريناه ، نريد محاكاة ما يلي بدقة: نريد انتظار التغييرات في واجهة المستخدم قبل البدء في التفاعل . في معظم الحالات ، نقصر هذا السلوك على العناصر التي نحتاجها ، وبالتالي باستخدام التأكيدات على تلك العناصر.
كما ترى ، يجب أن نجعل اختبارنا ينتظر في عدة مناسبات. ومع ذلك ، فإن الانتظار مرات عديدة ليس جيدًا أيضًا. كقاعدة عامة ، أقترح استخدام تأكيد للتحقق مما إذا كان العنصر المراد التفاعل معه قد تم تحميله بالكامل ، كخطوة أولى لتحديد ما إذا كان موقع الويب الذي يتم اختباره قد تم تحميله أم لا.
دعنا نلقي نظرة على هذا الجزء من اختبارنا كمثال. أضفت تأكيدًا واحدًا للتأكد من تحميل صفحتنا بالكامل :
// find-author-assertions.spec.js // Open website cy.visit('https://www.smashingmagazine.com'); // Ensure site is fully loaded cy.get('.headline-content').should('be.visible'); // Enter author's name in the search field cy.get('#js-search-input').type('Ramona Schwering');
استمر في إضافة التأكيدات بهذه الطريقة إلى جميع الحالات التي يكون فيها لموقعنا الإلكتروني أوقات تحميل أو عدة عناصر تحتاج إلى إعادة عرضها. للحصول على ملف الاختبار الكامل ، يرجى إلقاء نظرة على الاختبار المقابل في مستودع GitHub.
لتجنب الوقوع في فخ الاختبارات غير المستقرة ، أود أن أقدم لك تلميحًا أخيرًا: لا تستخدم أبدًا أوقات الانتظار الثابتة ، مثل cy.wait(500)
أو ما شابه.
ردود API هي أصدقائك
هناك إمكانية انتظار واحدة رائعة على وجه الخصوص أحب استخدامها في اختباراتي. في Cypress ، من الممكن العمل مع ميزات الشبكة - وهناك طريقة أخرى مفيدة للانتظار في تطبيقك وهي استخدام هذه الميزات للعمل مع طلبات الشبكة . بهذه الطريقة ، يمكنك جعل الاختبار ينتظر استجابة API ناجحة.
إذا تذكرنا سير العمل الخاص بنا كمثال ، يمكن لخطوة واحدة الاستفادة بشكل كبير من إمكانية انتظار واجهة برمجة التطبيقات. أفكر في البحث. يمكن أن تكون قصة المستخدم المقابلة كما يلي:
"بصفتي مطورًا ، أريد التأكد من تحميل نتائج البحث بالكامل حتى لا يؤدي أي مقال بالنتائج الأقدم إلى تضليل اختبارنا".
دعونا نطبق ذلك على اختبارنا. بادئ ذي بدء ، نحتاج إلى تحديد المسار الذي نريد انتظاره لاحقًا. يمكننا استخدام أمر intercept
لهذا الغرض. سأبحث عن الطلب ، وجلب البيانات التي أحتاجها - نتائج البحث في هذه الحالة.
للحفاظ على هذا المثال بسيطًا ، سأستخدم حرف بدل لعنوان URL. بعد ذلك ، سأستخدم اسمًا مستعارًا حتى يتمكن Cypress من العمل مع هذا المسار لاحقًا.
// find-author-hooks.spec.js // Set the route to work with it('Find the author Ramona Schwering', () => { // Route to wait for later cy.intercept({ url: '*/indexes/smashingmagazine/*', method: 'POST' }).as('search'); // With this alias Cypress will find the request again //...
في Cypress ، يتم عرض جميع المسارات المحددة في بداية الاختبار. لذا ، أود وضع أوامر intercept
هذه في بداية الاختبار أيضًا.
الآن ، يمكننا استخدام الاسم المستعار للمسار هذا في التأكيدات. أسهل طريقة للقيام بذلك هي باستخدام أمر wait
Cypress ، مباشرةً باستخدام الاسم المستعار المذكور سابقًا. ومع ذلك ، فإن استخدام هذا الأمر وحده سيؤدي إلى انتظار الاستجابة بغض النظر عن نتيجتها . حتى رموز الخطأ مثل 400 أو 500 تعتبر عابرة ، بينما من المرجح أن يتعطل تطبيقك. لذلك أوصي بإضافة تأكيد آخر مثل هذا:
// find-author-hooks.spec.js // Later: Assertion of the search request's status code cy.wait('@search') .its('response.statusCode').should('equal', 200);
بهذه الطريقة ، يمكننا انتظار بيانات البرنامج وتغييراته وما إلى ذلك بدقة ، دون إضاعة الوقت أو الوقوع في مشاكل إذا كان التطبيق شديد الضغط. مرة أخرى ، يمكنك العثور على ملف المثال الكامل في مستودع GitHub الخاص بي.
تكوين السرو
لقد تركت أحد التفاصيل الصغيرة. إذا ألقيت نظرة فاحصة على مثال الاختبار الكامل ، فإنه يختلف قليلاً عن تلك التي استخدمناها هنا في هذا الدليل.
// Cypress describe('Find author at smashing', () => { beforeEach(() => { // Open website cy.visit('https://www.smashingmagazine.com'); }); //...
أنا فقط استخدم الشرطة المائلة لفتح موقع مجلة Smashing Magazine. كيف يعمل هذا؟ حسنًا ، باستخدام هذا الأمر مثل ذلك سينتقل إلى baseUrl
في اختباراتنا. baseUrl
هي قيمة تكوين يمكن استخدامها كبادئة لعنوان URL الخاص بأمر cy.visit()
أو cy.request()
. من بين القيم الأخرى ، يمكننا تحديد هذه القيمة في ملف cypress.json
. بالنسبة للاختبار الذي أجريناه ، سنقوم بتعيين baseUrl
على النحو التالي:
// cypress.json { "baseUrl": "https://www.smashingmagazine.com" }
أذكر الشرفاء: خطاف
هناك موضوع واحد متبقي أريد أن أذكره ، حتى لو لم يكن اختبار المثال الخاص بنا مناسبًا لاستخدامه. كما هو شائع في أطر الاختبار الأخرى ، يمكننا تحديد ما يحدث قبل اختباراتنا وبعدها عبر ما يسمى بخطافات دورة الحياة . بتعبير أدق ، توجد هذه لتنفيذ التعليمات البرمجية قبل أو بعد واحد أو كل الاختبارات:
// Cypress describe('Hooks', function() { before(() => { // Runs once before all tests }); after(() => { // Runs once after all tests }); beforeEach(() => { // Runs before each test }); afterEach(() => { // Runs after each test }); });
نريد ملء ملف الاختبار الخاص بنا بأكثر من اختبار ، لذلك يجب أن نبحث عن الخطوات الشائعة التي نريد تنفيذها قبلها أو بعدها. السطر الأول لدينا هو مثال على ذلك ، وهو أمر visit
. بافتراض أننا نريد فتح موقع الويب هذا قبل كل اختبار من هذه الاختبارات ، فإن beforeEach
في مثالنا سيبدو كما يلي:
// Cypress describe('Find author at smashing', () => { beforeEach(() => { // Open website cy.visit('https://www.smashingmagazine.com'); }); //...
كثيرًا ما أستخدم هذا في عملي اليومي لضمان ، على سبيل المثال ، إعادة تعيين تطبيقي إلى حالته الافتراضية قبل الاختبار ، وبالتالي عزل الاختبار عن الاختبارات الأخرى. ( لا تعتمد أبدًا على الاختبارات السابقة! ) قم بإجراء اختباراتك بمعزل عن بعضها البعض للحفاظ على التحكم في حالة التطبيق.
يجب أن يكون كل اختبار قادرًا على إجراء الاختبار بمفرده - بغض النظر عن الاختبارات الأخرى. هذا أمر بالغ الأهمية لضمان نتائج اختبار صحيحة . للحصول على تفاصيل حول هذا ، راجع قسم "البيانات التي استخدمناها لمشاركتها" في إحدى مقالاتي الأخيرة. في الوقت الحالي ، راجع المثال الكامل على GitHub إذا كنت تريد رؤية الاختبار بالكامل.
خاتمة
في رأيي ، تعد الاختبارات الشاملة عنصرًا أساسيًا في CI ، حيث تحافظ على جودة التطبيقات على مستوى عالٍ وفي نفس الوقت تخفف من عمل المختبرين. Cypress هي أداتي المفضلة لتصحيح أخطاء الاختبارات من طرف إلى طرف بسرعة وثبات وكفاءة ، ولتشغيلها بالتوازي مع أي طلب سحب كجزء من CI. يكون منحنى التعلم لطيفًا إذا كنت معتادًا بالفعل على JavaScript.
آمل أن أكون قادرًا على إرشادك قليلاً ومنحتك نقطة بداية لكتابة اختبارات Cypress وبعض النصائح العملية للبدء. بالطبع ، تتوفر جميع أمثلة الأكواد في مستودع GitHub ، لذلك لا تتردد في إلقاء نظرة.
بالطبع ، هذه مجرد نقطة انطلاق. هناك العديد من الأشياء التي يجب تعلمها ومناقشتها فيما يتعلق باختبارات السرو - سأترك لك بعض الاقتراحات حول ما يجب تعلمه بعد ذلك. مع وضع هذا في الاعتبار ، اختبار سعيد!
موارد
- الأصل المحطم على سبيل المثال ، رامونا شفيرينغ
مستودع GitHub للمثال في هذه المقالة. - وثائق السرو
- "وصفات" ، السرو
مجموعة مختارة من الأمثلة والوصفات والدورات. - "تعلم البرمجة باستخدام JavaScript: Cypress" (درس) ، CodeLikeThis
- أفضل الممارسات في كتابة الاختبارات الشاملة "، Shopware Docs