اختبار طلب HTTP: أداة بقاء المطور

نشرت: 2022-03-11

ماذا تفعل عندما تكون مجموعة الاختبار غير مجدية

هناك أوقات نمتلك فيها - المبرمجين و / أو عملائنا - موارد محدودة يمكننا من خلالها كتابة كل من الناتج المتوقع والاختبارات الآلية لهذا التسليم. عندما يكون التطبيق صغيرًا بما يكفي ، يمكنك قطع الزوايا وتخطي الاختبارات لأنك تتذكر (غالبًا) ما يحدث في مكان آخر في الكود عند إضافة ميزة أو إصلاح الخلل أو إعادة البناء. ومع ذلك ، فإننا لن نعمل دائمًا مع التطبيقات الصغيرة ، بالإضافة إلى أنها تميل إلى أن تصبح أكبر وأكثر تعقيدًا بمرور الوقت. هذا يجعل الاختبار اليدوي صعبًا ومزعجًا للغاية.

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

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

الاختبار الآلي

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

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

وحدة التجارب

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

 test “should return active users” do active_user = create(:user, active: true) non_active_user = create(:user, active: false) result = User.active assert_equal result, [active_user] end

الاختبار الوظيفي

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

ملاحظة: جميع الأمثلة لدينا موجودة في Ruby.

 test "should get index" do get :index assert_response :success assert_not_nil assigns(:object) end

اختبار التكامل

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

 test "login and browse site" do # login via https https! get "/login" assert_response :success post_via_redirect "/login", username: users(:david).username, password: users(:david).password assert_equal '/welcome', path assert_equal 'Welcome david!', flash[:notice] https!(false) get "/articles/all" assert_response :success assert assigns(:articles) end

الاختبارات في عالم مثالي

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

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

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

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

الاختبارات في العالم الحقيقي

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

الوقت / المواعيد النهائية

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

قضايا العميل

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

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

نقص المعرفة

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

'انها هناك الكثير من العمل'

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

أخيرًا وليس آخرًا ، من الصعب كتابة الاختبارات وطلاب علوم الكمبيوتر غير مدربين عليها.

أوه ، وإعادة الهيكلة مع اختبارات الوحدة ليست متعة.

اختلاف في الرأي

في رأيي ، يعتبر اختبار الوحدة منطقيًا لمنطق الخوارزمية ولكن ليس كثيرًا لتنسيق الكود الحي.

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

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

لكنك تحتاج إلى نوع من الاختبار

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

ما أستخدمه بدلاً من ذلك

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

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

الموضوعات ذات الصلة: وظف أفضل 3٪ من مهندسي ضمان الجودة المستقلين.

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

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

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

عمليًا: الاختبار باستخدام طلبات HTTP

نظرًا لأننا أثبتنا بالفعل أن كتابة الكود بدون أي نوع من الاختبارات المصاحبة ليست فكرة جيدة ، فإن اختبار go-to الأساسي الخاص بي لتطبيق كامل هو إرسال طلبات HTTP إلى جميع صفحاته محليًا وتحليل رؤوس الاستجابة للحصول على 200 (أو المطلوب) كود.

على سبيل المثال ، إذا كتبنا الاختبارات المذكورة أعلاه (تلك التي تبحث عن محتوى معين وخطأ فادح) مع طلب HTTP بدلاً من ذلك (في Ruby) ، فسيكون شيء من هذا القبيل:

 # testing for fatal error http_code = `curl -X #{route[:method]} -s -o /dev/null -w "%{http_code}" #{Rails.application.routes.url_helpers.articles_url(host: 'localhost', port: 3000) }` if http_code !~ /200/ return “articles_url returned with #{http_code} http code.” end # testing for content active_user = create(:user, name: “user1”, active: true) non_active_user = create(:user, name: “user2”, active: false) content = `curl #{Rails.application.routes.url_helpers.active_user_url(host: 'localhost', port: 3000) }` if content !~ /#{active_user.name}/ return “Content mismatch active user #{active_user.name} not found in text body” #You can customise message to your liking end if content =~ /#{non_active_user.name}/ return “Content mismatch non active user #{active_user.name} found in text body” #You can customise message to your liking end

الخط curl -X #{route[:method]} -s -o /dev/null -w "%{http_code}" #{Rails.application.routes.url_helpers.articles_url(host: 'localhost', port: 3000) } يغطي الكثير من حالات الاختبار ؛ سيتم اكتشاف أي طريقة تؤدي إلى حدوث خطأ في صفحة المقالة هنا ، لذا فهي تغطي بشكل فعال مئات الأسطر من التعليمات البرمجية في اختبار واحد.

الجزء الثاني ، الذي يمسك خطأ المحتوى على وجه التحديد ، يمكن استخدامه عدة مرات للتحقق من المحتوى على الصفحة. (يمكن معالجة الطلبات الأكثر تعقيدًا باستخدام mechanize ، لكن هذا خارج نطاق هذه المدونة.)

الآن ، في الحالات التي تريد فيها اختبار ما إذا كانت صفحة معينة تعمل على مجموعة كبيرة ومتنوعة من قيم قاعدة البيانات (على سبيل المثال ، يعمل قالب صفحة المقالة الخاصة بك مع جميع المقالات في قاعدة بيانات الإنتاج) ، يمكنك القيام بما يلي:

 ids = Article.all.select { |post| `curl -s -o /dev/null -w “%{http_code}” #{Rails.application.routes.url_helpers.article_url(post, host: 'localhost', port: 3000) }`.to_i != 200).map(&:id) return ids

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

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

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

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

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

اختبار واحد

تحقق من عودة الصفحة دون أي أخطاء فادحة.

اختبار واحد يتحقق من عودة الصفحة دون أي أخطاء فادحة.

لاحظ كيف أنشأت قائمة بجميع نقاط النهاية لـ Post وقمت بتكرارها للتحقق من عرض كل صفحة دون أي خطأ. بافتراض أن كل شيء سار على ما يرام ، وتم عرض جميع الصفحات ، فسترى شيئًا كهذا في الجهاز: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of failed url(s) -- []

إذا لم يتم عرض أي صفحة ، فسترى شيئًا من هذا القبيل (في هذا المثال ، تحتوي posts/index page على خطأ وبالتالي لا يتم عرضها): ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of failed url(s) -- [{:url=>”posts_url”, :params=>[], :method=>”GET”, :http_code=>”500”}]

الاختبار الثاني

تأكد من وجود كل المحتوى المتوقع:

يؤكد الاختبار الثاني أن كل المحتوى المتوقع موجود.

إذا تم العثور على كل المحتوى الذي نتوقعه على الصفحة ، فستبدو النتيجة كما يلي (في هذا المثال نتأكد من أن posts/:id لها عنوان منشور ووصف وحالة): ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of content(s) not found on Post#show page with post id: 1 -- []

إذا لم يتم العثور على أي محتوى متوقع في الصفحة (نتوقع هنا أن تعرض الصفحة حالة النشر - "نشط" إذا كان المنشور نشطًا ، و "معطل" إذا تم تعطيل النشر) ، فستبدو النتيجة كما يلي: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of content(s) not found on Post#show page with post id: 1 -- [“Active”]

الاختبار الثالث

تحقق من عرض الصفحة عبر جميع مجموعات البيانات (إن وجدت):

يتحقق الاختبار 3 من أن الصفحة يتم عرضها عبر جميع مجموعات البيانات.

إذا تم عرض جميع الصفحات دون أي خطأ ، فسنحصل على قائمة فارغة: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of post(s) with error in rendering -- []

إذا كان محتوى بعض السجلات به مشكلة في العرض (في هذا المثال ، تظهر الصفحات ذات المعرفين 2 و 5 خطأ) ، فستبدو النتيجة كما يلي: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of post(s) with error on rendering -- [2,5]

إذا كنت تريد العبث برمز العرض أعلاه ، فإليك مشروع جيثب الخاص بي.

إذن أيهما أفضل؟ هذا يعتمد…

قد يكون اختبار طلب HTTP هو أفضل رهان لك إذا:

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

يُعد الاختبار التقليدي مثاليًا عندما:

  • أنت تتعامل مع شيء آخر غير تطبيق الويب ، مثل البرامج النصية
  • أنت تكتب كودًا معقدًا وخوارزميًا
  • لديك الوقت والميزانية لتكريسها لكتابة الاختبارات
  • يتطلب العمل معدل خطأ أو خالي من الأخطاء (التمويل ، قاعدة مستخدمين كبيرة)

شكرا لقرائتك المجلة؛ يجب أن يكون لديك الآن طريقة للاختبار يمكنك اتباعها بشكل افتراضي ، طريقة يمكنك الاعتماد عليها عند الضغط عليك للوقت.

متعلق ب:
  • الأداء والكفاءة: العمل مع HTTP / 3
  • احتفظ به مشفرًا وحافظ عليه آمنًا: العمل مع ESNI و DoH و DoT