JavaScript هي لغة نوع ديناميكية ، والتي تمنحها قدرة أداء قوية ، ولكنها تجعل المترجم تقريبًا من المستحيل تقديم أي مساعدة للمطورين. لهذا السبب ، نشعر أن كتابة أي رمز JavaScript يجب أن يكون له مجموعة قوية وكاملة من الاختبارات. يحتوي Angular على العديد من الميزات التي تسهل علينا اختبار تطبيقاتنا. لا ينبغي أن يكون لدينا عذر بعدم كتابة الاختبارات (هذا هو ...).
1. الأمر كله يتعلق بعدم خلط المخاوف (الأمر كله يتعلق بتجنب أن تصبح علاقة الكود معقدة ...)
اختبار الوحدة ، كاسم ، يدور حول اختبار "وحدة" واحدة. يسعى اختبار الوحدة إلى الإجابة على هذه الأسئلة: هل أنا بالفعل محقون في اعتبارات المنطق الخاصة بي؟ هل النتائج التي تم الحصول عليها بواسطة طريقة الفرز صحيحة؟ للإجابة على هذه الأسئلة ، من المهم بشكل خاص فصلها. هذا لأنه عندما نختبر طريقة الفرز ، لا نريد الاهتمام بشظايا أخرى ذات صلة ، مثل عناصر DOM أو بدء طلبات XHR للحصول على البيانات ، وما إلى ذلك. من الواضح أنه من الصعب عادة استدعاء وظيفة بشكل منفصل في مشروع نموذجي. سبب هذه المشكلة هو أن المطورين غالبًا ما يجعلون العلاقات معقدة وينتهي بهم الأمر إلى جعل مقتطفًا يبدو أنه يمكن أن يفعل كل شيء. يحصل على البيانات من خلال XHR ، وفرز البيانات ، ثم يعالج DOM. جنبا إلى جنب مع Angular يمكننا كتابة رمز أفضل بسهولة أكبر ، لذلك يوفر لنا Angular حقن التبعية من XHR (والتي يمكننا محاكاة) و Angular أيضًا تخلق تجريدات تسمح لنا بفرز النموذج دون معالجة DOM. لذلك ، في النهاية ، يمكننا ببساطة كتابة طريقة فرز ، ثم إنشاء مجموعة بيانات من خلال حالة الاختبار لاستخدام طريقة الفرز عند الاختبار ، ثم تحديد ما إذا كان نموذج النتيجة يفي بالتوقعات. لا يتطلب الاختبار انتظار XHR لإنشاء DOM المقابل وتحديد ما إذا كانت الوظيفة تعمل DOM بشكل صحيح. تتضمن الفكرة الأساسية لـ Angular قابلية اختبار الكود ، ولكنها تتطلب أيضًا منا أن نفعل الشيء الصحيح. تلتزم Angular بتبسيط طريقة القيام بالشيء الصحيح ، لكن Angular ليس سحريًا ، مما يعني أننا قد ينتهي بنا المطاف بتطبيق غير قابل للاختبار إذا لم نتبع النقاط التالية.
1. حقن التبعية
هناك العديد من الطرق للحصول على موارد التبعية: 1) يمكننا استخدام المشغل الجديد ؛ 2) نستخدم طريقة معروفة تسمى "Global Singleton" ؛ 3) يمكننا أن نطلبها من خدمة التسجيل (ولكن كيف نحصل على سجل؟ يمكنك التحقق من الفصول التالية) ؛ 4) يمكننا أن نتوقع أن يتم تمريرها.
من الأساليب المذكورة أعلاه ، فإن آخر طريقة قابلة للاختبار ، دعنا نرى لماذا:
1) استخدام المشغل الجديد
لا توجد أخطاء في الأساس عند استخدام المشغل الجديد ، ولكن المشكلة هي أن استدعاء المُنشئ من خلال New سوف يربط المتصل بشكل دائم بالنوع. على سبيل المثال ، نحاول إنشاء كائن XHR حتى نتمكن من الحصول على بعض البيانات من الخادم.
الدالة myClass () {this.dowork = function () {var xhr = new xrh () ؛ XHR.Open (الطريقة ، URL ، صواب) ؛ XHR.OnReadyStateChange = function () {...} ؛ xhr.send () ؛ }}المشكلة هي أنه عند الاختبار ، عادة ما نحتاج إلى إنشاء مثيل لـ XHR الظاهري الذي يمكنه إرجاع بيانات الاختبار أو أخطاء الشبكة. من خلال استدعاء New XHR () ، نربط بشكل دائم XHR الحقيقي ، وليس هناك طريقة جيدة لاستبدالها. بالطبع ، هناك علاج سيء وهناك العديد من الأسباب لإثبات أنها فكرة سيئة:
var oldxhr = xhr ؛ xhr = new mockxhr () {} ؛ myclass.dowork () ؛ // الحكم على ما إذا كان mockxhr يدعو xhr = oldxhr من خلال المعلمات العادية ؛ // إذا نسيت هذه الخطوة ، فمن السهل التسبب في أشياء حزينة.2) البحث العالمي
هناك طريقة أخرى لحل المشكلة وهي الحصول على موارد التبعية في مكان معروف.
الدالة myClass () {this.dowork = function () {global.xhr ({...}) ؛ } ؛}دون إنشاء مثيل لكائن جديد تابع ، فإن المشكلة هي في الأساس مثل الجديد ، وليس هناك طريقة جيدة لاعتراض مكالمات Global.xHR عند الاختبار. المشكلة الأساسية في الاختبار هي أنه يجب تغيير المتغيرات العالمية لاستدعاء الأساليب الافتراضية وتعديلها. لمعرفة المزيد حول عيوبها ، تفضل بزيارة هنا: http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/
من الصعب اختبار الرمز أعلاه ، لذلك يجب علينا تعديل الحالة العالمية:
var oldxhr = global.xhr ؛ global.xhr = function mockxhr () {...} ؛ var myclass = new myclass () ؛ // just ما إذا كان mockxhr يدعو global.xhr = oldxhr من خلال المعلمات العادية ؛ // إذا نسيت هذه الخطوة ، فمن السهل أن تسبب الأشياء الحزينة.3) سجل الخدمة
يبدو أن وجود سجل مع جميع الخدمات يحل المشكلة ، ثم استبدال الخدمة المطلوبة في رمز الاختبار.
وظيفة myClass () {var serviceRegistry = ؟؟؟ ؛ this.dowork = function () {var xhr = serviceRegistry.get ("XHR") ؛ ...} ؛}ولكن من أين تأتي التحليل من الخدمة؟ إذا كان الأمر كذلك: * new-ed Up ، فلا يوجد لديه فرصة لإعادة ضبط الخدمات للاختبار * البحث العالمي ، فإن الخدمة التي تم إرجاعها هي عالمية أيضًا (ولكن إعادة التعيين أسهل ، نظرًا لوجود متغير عالمي واحد فقط يتم إعادة تعيينه) (النص وراء هنا هو نفسه مثل المشتركة ... لم أفهم)
وفقًا لهذه الطريقة ، قم بتعديل الفئة أعلاه إلى الطريقة التالية:
var oldservicelocator = global.servicelocator ؛ global.servicelocator.set ('xhr' ، function mockxhr () {}) ؛ var myclass = new myclass () ؛ myclass.dowork () ؛ // // إذا نسيت هذه الخطوة ، فمن السهل التسبب في أشياء حزينة.4) المرور في التبعيات
أخيرًا ، يمكن تمرير موارد التبعية.
دالة myClass (xhr) {this.dowork = function () {xhr ({...}) ؛ } ؛}هذه هي الطريقة المفضلة ، لأن الرمز لا يحتاج إلى الانتباه إلى المكان الذي يأتي منه XHR ، ولا يهتم به من قام بإنشاء XHR. لذلك ، يمكن تشفير خالق الفصل بشكل منفصل عن مستهلك الفصل ، والذي يفصل بين مسؤولية الخلق عن المنطق ، وهو لمحة عامة عن الحقن التبعي.
من السهل اختبار هذا الفصل ، ويمكننا كتابته مثل هذا في الاختبار:
وظيفة XHRMock (args) {...} var myClass = new MyClass (xhrmock) ؛ myclass.dowrok () ؛ // إصدار بعض الأحكام ... من خلال رمز الاختبار هذا ، يمكننا أن ندرك أنه لا توجد متغيرات عالمية تالف.تبعية الحقن (//www.vevb.com/article/91775.htm) المضمنة مع الزاوي ، رمز مكتوبة بهذه الطريقة يجعل من السهل كتابة رمز الاختبار. إذا أردنا كتابة رمز يمكن اختباره بشكل كبير ، فمن الأفضل أن نستخدمه.
2. وحدات التحكم
المنطق يجعل كل تطبيق فريدًا ، وهذا ما نريد اختباره. إذا تم خلط منطقنا مع عمليات DOM ، فسيكون من الصعب اختبار هذا المثال التالي:
وظيفة PasswordController () {// احصل على مرجع إلى كائن DOM var msg = $ ('. ex1 span') ؛ var input = $ ('. ex1 input') ؛ فاف قوة this.grade = function () {msg.removeClass (قوة) ؛ var pwd = input.val () ؛ password.text (pwd) ؛ if (pwd.length> 8) {strength = 'strong' ؛ } آخر إذا (pwd.length> 3) {strength = 'medium' ؛ } else {strength = 'dep' ؛ } msg.addclass (قوة) .Text (القوة) ؛ }}سيواجه الرمز أعلاه مشاكل عند الاختبار لأنه يتطلب منا الحصول على DOM الصحيح عند تنفيذ الاختبار. سيكون رمز الاختبار كما يلي:
var input = $ ('<input type = "text"/>') ؛ var span = $ ('<span>') ؛ $ ('body'). PasswordController () ؛ input.val ('abc') ؛ pc.grade () ؛ توقع (span.text ()).في Angular ، تفصل وحدة التحكم بصرامة لمنطق عملية DOM ، مما سيقلل بشكل كبير من صعوبة كتابة حالات اختبار. ألق نظرة على المثال التالي:
وظيفة passwordcntrl ($ scope) {$ scope.password = '' '؛ $ scope.grade = function () {var size = $ scope.password.length ؛ if (size> 8) {$ scope.strength = 'strong' ؛ } آخر إذا (size> 3) {$ scope.strength = 'medium' ؛ } آخر {$ scope.strength = 'pear' ؛ }} ؛}رمز الاختبار واضح ومباشر:
var pc = new PasswordController ($ scope) ؛ pc.password ('abc') ؛ pc.grade () ؛ توقع ($ scope.strength) .tequal ('الضعيف') ؛تجدر الإشارة إلى أن رمز الاختبار ليس فقط أكثر انقطاعًا ، ولكن من الأسهل تتبعه. لقد قلنا دائمًا أن قضايا الاختبار تحكي قصصًا ، وليس الحكم على أشياء أخرى غير ذات صلة.
3. المرشحات
مرشح (http://docs.angularjs.org/api/ng.$filter) يستخدم لتحويل البيانات إلى تنسيق سهل الاستخدام. إنها مهمة لأنها تفصل بين مسؤولية تحويل التنسيقات عن منطق التطبيق ، مما يزيد من تبسيط منطق التطبيق.
mymodule.filter ('length' ، function () {return function (text) {return (''+(text || '')4. التوجيهات
5. يسخر
6. عزل الدولة العالمية
7. طريقة الاختبار المفضلة
8. JavaScriptTestDriver
9. ياسمين
10. عينة مشروع
سنستمر في تحديث المقالات ذات الصلة في المستقبل. شكرا لك على دعمك لهذا الموقع!