كيفية إنشاء تطبيقات React قوية مع TDD ومكتبة React Testing

أحد الأشياء التي واجهتها عندما بدأت في تعلم React كان اختبار تطبيقات الويب الخاصة بي بطريقة مفيدة وبديهية. لقد استخدمت الإنزيم مع Jest لتقديم ضحل في كل مرة كنت أرغب في اختباره.

بالطبع ، كنت أسيء استخدام ميزة اختبار اللقطة.

حسنًا ، على الأقل كتبت اختبارًا صحيحًا؟

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

لقد حضرت مؤخرًا ورشة عمل من خلال Workshop.me مع Kent C. Dodds حيث علمنا كيفية كتابة اختبارات تكامل أفضل لتطبيقات React.

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

في هذه المقالة ، سوف نتعلم ممارسة TDD من أجل بناء تطبيقات React الصلبة عن طريق إنشاء خلاصة تعليق. بالطبع ، تنطبق هذه العملية على كل تطوير البرامج ، وليس فقط تطبيقات React أو JavaScript.

ابدء

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

إنشاء رد فعل التطبيق تغذية التعليقات
مؤتمر نزع السلاح التعليق تغذية
غزل

كما هو الحال ، يمكننا إزالة جميع الملفات في دليل src باستثناء index.js. ثم ، داخل مجلد src مباشرةً ، قم بإنشاء مجلد جديد يسمى المكونات ومجلد آخر يسمى الحاويات.

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

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

لا نريد اختبار تفاصيل التنفيذ بعد الآن. نريد تقديم عنصر ومعرفة ما إذا كانت الأشياء الصحيحة تحدث عندما نقر أو نغير شيئًا ما على واجهة المستخدم. هذا هو! لا مزيد من التحقق مباشرة الدعائم أو أسماء الولاية أو الفئة.

دعونا تثبيتها والبدء في العمل.

الغزل إضافة رد فعل اختبار المكتبة

بناء التعليق تغذية مع TDD

دعونا نفعل هذا المكون الأول على غرار TDD. اطلاق النار حتى عداء الاختبار الخاص بك.

اختبار الغزل - ساعة

داخل مجلد الحاويات ، سنقوم بإضافة ملف يسمى CommentFeed.js. بجانبه ، أضف ملفًا يسمى CommentFeed.test.js. بالنسبة للاختبار الأول ، دعونا نتحقق من أنه يمكن للمستخدمين إنشاء تعليقات. قريبا جدا؟ حسنًا ، نظرًا لعدم وجود أي رمز بعد ، سنبدأ باختبار أصغر. دعونا نتحقق من أنه يمكننا تقديم الخلاصة.

بعض الملاحظات على مكتبة اختبار التفاعل

أولاً ، دعونا نلاحظ وظيفة العرض هنا. إنه مشابه للطريقة التي يعرض بها رد الفعل doment عنصرًا على DOM ، ولكنه يُرجع كائنًا يمكننا تدميره للحصول على بعض مساعدي الاختبار الأنيقين. في هذه الحالة ، نحصل على queryByText ، والذي ، بالنظر إلى بعض النصوص التي نتوقع رؤيتها على DOM ، سيعيد عنصر HTML هذا.

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

  • getByLabelText (مدخلات النموذج)
  • getByPlaceholderText (فقط إذا كان الإدخال الخاص بك لا يحتوي على تصنيف - يمكن الوصول إليه بشكل أقل!)
  • getByText (أزرار ورؤوس)
  • getByAltText (صور)
  • getByTestId (استخدم هذا لأشياء مثل النص الديناميكي أو العناصر الفردية التي تريد اختبارها)

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

إذا لم تحصل أي منها على ما تبحث عنه بالضبط ، فإن طريقة التجسيد تُرجع أيضًا عنصر DOM المعين إلى خاصية الحاوية ، بحيث يمكنك استخدامه مثل container.querySelector (‘body #root’).

قانون التنفيذ الأول

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

قد يكون الأمر أسوأ - أقصد ، كنت على وشك أن أكتب هذه المقالة بأكملها أثناء تصميم المكونات. لحسن الحظ ، لا تهتم الاختبارات كثيرًا بالأنماط ، لذلك يمكننا التركيز على منطق التطبيق لدينا.

سوف يتحقق هذا الاختبار التالي من أنه يمكننا تقديم تعليقات. لكن ليس لدينا أي تعليقات ، لذلك دعونا نضيف هذا المكون أيضًا. بعد الاختبار رغم ذلك.

سأقوم أيضًا بإنشاء كائن الدعائم لتخزين البيانات التي قد نعيد استخدامها في هذه الاختبارات.

في هذه الحالة ، أتحقق من أن عدد التعليقات يساوي عدد العناصر التي تم تمريرها في CommentFeed. إنه تافه ، لكن فشل الاختبار يمنحنا الفرصة لإنشاء ملف Comment.js.

هذا الضوء الأخضر لدينا مجموعة اختبار حتى نتمكن من المضي قدما دون خوف. جميع البرد TDD ، المنقذ من نوعنا. إنه يعمل عندما نعطيه مجموعة فارغة ، بالطبع. ولكن ماذا لو أعطيناها بعض الأشياء الحقيقية؟

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

آه انظر إلى ذلك ، لقد مر اختبارنا مرة أخرى. ها هي لقطة رائعة لجمالها.

لاحظ كيف لم أقل أبدا مرة واحدة أنه ينبغي لنا إطلاق برنامجنا مع بدء الغزل؟ سنبقيها بهذه الطريقة لفترة من الوقت. وهذه النقطة هي ، يجب أن تشعر رمز مع عقلك.

التصميم هو فقط ما هو في الخارج - إنه في الداخل ما يهم.

فقط إذا كنت ترغب في بدء التطبيق ، فقم بتحديث index.js إلى ما يلي:

إضافة نموذج التعليق

هذا هو المكان الذي تبدأ فيه الأمور في الحصول على مزيد من المرح. هذا هو المكان الذي ننتقل فيه من التحقق من النعاس لوجود العقد DOM إلى فعل الأشياء بالفعل مع ذلك والتحقق من السلوك. كل ما كان الاشياء الاخرى الاحماء.

لنبدأ بوصف ما أريد من هذا النموذج. يجب:

  • يحتوي على إدخال النص للمؤلف
  • يحتوي على إدخال النص ثم تعليق نفسه
  • لديك زر إرسال
  • قم في النهاية باستدعاء واجهة برمجة التطبيقات (API) أو أي خدمة تتولى إنشاء وتخزين التعليق.

يمكننا إنزال هذه القائمة في اختبار تكامل واحد. بالنسبة لحالات الاختبار السابقة ، أخذناها ببطء شديد ، لكننا الآن سنحاول رفع السرعة ونحاول تثبيتها في ضربة واحدة.

لاحظ كيف تتطور مجموعة الاختبار الخاصة بنا؟ لقد انتقلنا من الدعائم القوية الترميز داخل حالات الاختبار الخاصة بهم إلى إنشاء مصنع لهم.

ترتيب ، التصرف ، تأكيد

يمكن تقسيم اختبار التكامل التالي هذا إلى ثلاثة أجزاء: الترتيب والتصرف والتأكيد.

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

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

عند العثور على المدخلات ، نريد أن نحاول العثور عليها حسب علاماتها. هذا يعطي الأولوية للوصول عندما نبني تطبيقاتنا. أسهل طريقة للاستيلاء على النموذج هي باستخدام container.querySelector.

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

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

بعد تقديم النموذج ، يمكننا تقديم تأكيدات على أشياء مثل الدعائم التي تم الاحتجاج بها وبأي حجج. يمكننا أيضًا استخدام هذه اللحظة للتحقق من مسح مدخلات النموذج.

هل هو مخيف؟ لا داعي للخوف يا طفلي ، المشي بهذه الطريقة. ابدأ بإضافة النموذج إلى وظيفة التجسيد.

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

هذه هي طريقة TDD. عندما يبدو شيء ما وكأنه يمكن إعادة تشكيله ، قم بتدوين ذلك والمضي قدمًا. Refactor فقط عندما يكون وجود تجريد مفيدًا لك ولا تشعر بأنه غير ضروري.

أتذكر عندما قمنا بإعادة تشكيل مجموعة الاختبار الخاصة بنا عن طريق إنشاء مصنع createProps؟ مثل هذا تماما. يمكننا اختبارات refactor ، أيضا.

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

وهذا ما فعله. لقد مرت اختباراتنا ولدينا شيء يشبه التطبيق الحقيقي. كيف تبدو تغطيتنا؟

ليس سيئا. إذا تجاهلنا جميع الإعدادات التي تدخل index.js ، فلدينا تطبيق ويب مغطى بالكامل فيما يتعلق بالخطوط المنفذة.

بالطبع ، ربما هناك حالات أخرى نريد اختبارها للتحقق من أن التطبيق يعمل كما نعتزم. رقم التغطية هذا مجرد شيء يمكن لرئيسك التباهي به عندما يتحدث إلى الأتراب الآخرين.

تروق التعليقات

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

سيتم تمرير خاصية المصادقة الخاصة بالمستخدم عبر المصادقة على التطبيق. سيتم ملاحظة أي إجراءات ذات صلة بما إذا كانت مصادقة.

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

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

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

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

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

دعنا "نحب" تعليق. أضف حالة الاختبار التالية هذه ثم قم بتحديث المصنع الدعائي ليشمل likeComment.

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

أضع معرف الاختبار مباشرة على الزر حتى نتمكن من محاكاة نقرة على الفور دون الحاجة إلى تداخل محددات الاستعلام. كما أرفقت معالج onClick إلى الزر بحيث يستدعي وظيفة onLike التي تم تمريرها إليه.

الآن نضيف فقط طريقة الفصل هذه إلى CommentFeed:

قد تتساءل عن سبب عدم قيامنا ببساطة بتمرير الرمز "أعجبني" مباشرة إلى مكون التعليق. لماذا نجعلها ملكية مميزة؟

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

أن تكون قادرًا على تجميع عدة استدعاءات وظائف مختلفة في طريقة handleLike لمكون الحاوية له ميزاته. يمكننا أيضًا استخدام هذه الطريقة لتحديث حالة المكون بعد "أعجبني" بنجاح إذا اخترنا ذلك.

كره التعليقات

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

قد تلاحظ أيضًا أن المنطق الذي نختبره هش وغير قابل للتطبيق بشكل رهيب على موجز تعليقات في العالم الحقيقي. على سبيل المثال ، ماذا لو حاولنا تعليقًا أعجبنا بالفعل؟ هل ستزيد عدد مرات الإعجاب إلى أجل غير مسمى أم أنها ستعكس ذلك؟ هل يمكن أن يعجبني تعليقي الخاص؟

سأترك تمديد وظيفة المكونات إلى خيالك ، ولكن بداية جيدة ستكون لكتابة حالة اختبار جديدة. في ما يلي الافتراض بأننا نرغب في تنفيذ تعليق لم يعجبنا:

لاحظ أن خلاصة التعليقات التي نبنيها تتيح لي الإعجاب بتعليقاتي. من يفعل ذلك؟

لقد قمت بتحديث مكون التعليق مع بعض المنطق لتحديد ما إذا كان المستخدم الحالي يحب التعليق أم لا.

حسناً ، لقد خدعت قليلاً: حيث كنا نمرر المؤلف إلى وظيفة onLike من قبل ، لقد غيرت إلى currentUser ، وهو دعم المصادقة الذي تم تمريره إلى مكون التعليق.

بعد كل شيء ، لن يكون من المنطقي أن يظهر مؤلف التعليق عندما يحب شخص آخر تعليقه.

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

ولكن لا يوجد جهل هنا ، فقط الاختبارات والرمز الذي يتبع. تأكد من تحديث CommentFeed بحيث يتوقع تمرير خاصية المصادقة. بالنسبة إلى معالجات onClick ، ​​يمكننا أن نتجاهل المرور حول خاصية المصادقة ، حيث يمكننا استخلاص ذلك من خاصية المصادقة في مقبض الوالد مثل طرق التعامل مع الطريقة الثنائية.

تغليف

نأمل أن يشبه جناح الاختبار شجرة عيد الميلاد غير المضاءة.

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

على سبيل المثال ، لنفترض أنك تريد بالفعل تطبيق handleLike والتعامل مع Dislike في طريقة فردية واحدة ، ولكن لديك أولويات أخرى الآن. يمكنك القيام بذلك عن طريق التوثيق في حالة اختبار مثل:

هذا لا يعني أنك بحاجة إلى كتابة اختبار جديد تمامًا. يمكنك أيضًا تحديث الحالتين السابقتين. ولكن النقطة المهمة هي أنه يمكنك استخدام عداء الاختبار كقائمة "مهمة" أكثر إلحاحًا للتطبيق الخاص بك.

روابط مفيدة

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

  • "تقديم مكتبة اختبار التفاعل" لكنت دودز ، من الجيد فهم الفلسفة الكامنة وراء مكتبة الاختبار هذه.
  • "البرمجيات المضادة للأنماط المضادة" للكاتب Kostis Kapelonis ، مقالة متعمقة للغاية تناقش اختبار الوحدة والتكامل ، وكذلك كيف لا تفعلها.
  • "اختبار يحركه التطوير بالقدوة" لكنت بيك. هذا كتاب مادي يناقش أنماط TDD. إنه ليس طويلًا ، وهو مكتوب بشكل تحادثي ، مما يسهل عملية الهضم.

آمل أن يقلبك بعض الوقت.

هل لديك فضول لمزيد من المشاركات أو تصريحات بارعة؟ إذا كنت قد استمتعت بهذا المقال ، فامنحني بعض التصفيقات واتبعني على "متوسط" و "جيثب" و "تويتر"!