الجزء الثاني من البرنامج التعليمي لتطبيق AngularJS الخاص بك: أدوات السقالات والبناء والاختبار
نشرت: 2022-03-11مقدمة
مع العديد من الأدوات المتاحة للمساعدة في تطوير تطبيقات AngularJS ، لدى الكثير من الناس انطباع بأنه إطار عمل معقد للغاية ، وهذا ليس هو الحال على الإطلاق. هذا هو أحد الأسباب الرئيسية التي دفعتني لبدء هذه السلسلة التعليمية.
في الجزء الأول ، غطينا أساسيات إطار عمل AngularJS وبدأنا بكتابة تطبيقنا الأول. هذا المنشور مصمم للمبتدئين. إذا كنت مطور AngularJS أكثر خبرة ، فقد تكون مهتمًا أكثر بإزالة الغموض عن التوجيهات أو قصة AngularJS قيد الاستخدام في شركة ناشئة.
في هذا البرنامج التعليمي ، سنضع طبقة منطق التطبيق جانبًا ونتعلم كيفية إجراء إعداد مشروع AngularJS المناسب ، بما في ذلك السقالات وإدارة التبعية وتحضيرها للاختبار (كل من الوحدة والنهاية). سنفعل ذلك باستخدام أدوات AngularJS هذه: Yeoman و Grunt و Bower. بعد ذلك ، سنراجع عملية كتابة وتشغيل اختبارات الياسمين باستخدام الكارما.
كارما ، ياسمين ، جرانت ، باور ، يومان ... ما كل هذه الأدوات؟
إذا كنت تعمل باستخدام JavaScript ، فمن المحتمل جدًا أنك تعرف بالفعل على الأقل بعض هذه الأدوات ، حتى لو كنت جديدًا على Angular. ولكن للمساعدة في ضمان خط أساس مشترك ، سأتجنب وضع أي افتراضات. دعنا نراجع بإيجاز كل من هذه التقنيات وما هي فائدتها:
Karma (المعروفة سابقًا باسم Testacular) هي عداء اختبار JavaScript من Google والاختيار الطبيعي لاختبار AngularJS. بالإضافة إلى السماح لك بإجراء اختباراتك على متصفحات حقيقية (بما في ذلك متصفحات الهاتف / الجهاز اللوحي) ، فهي أيضًا عبارة عن اختبار إطار حيادي ؛ مما يعني أنه يمكنك استخدامه جنبًا إلى جنب مع أي إطار اختبار من اختيارك (مثل Jasmine أو Mocha أو QUnit ، من بين أمور أخرى).
سيكون الياسمين هو إطار الاختبار المفضل لدينا ، على الأقل لهذا المنشور. تركيبها مشابه تمامًا لتلك الموجودة في RSpec ، إذا كنت قد عملت مع ذلك من قبل. (إذا لم تكن قد فعلت ذلك ، فلا تقلق ؛ سوف نتحقق من ذلك بمزيد من التفصيل لاحقًا في هذا البرنامج التعليمي.)
Grunt هو عداء مهام يساعد على أتمتة العديد من المهام المتكررة ، مثل التصغير والتجميع (أو الإنشاء) والاختبار وإعداد معاينة لتطبيق AngularJS الخاص بك.
Bower هو مدير حزم يساعدك في العثور على جميع تبعيات التطبيقات وتثبيتها ، مثل أطر CSS ومكتبات JavaScript وما إلى ذلك. يتم تشغيله عبر git ، مثل حزمة Rails ، ويتجنب الحاجة إلى تنزيل التبعيات وتحديثها يدويًا.
Yeoman عبارة عن مجموعة أدوات تحتوي على 3 مكونات أساسية: Grunt و Bower وأداة السقالات Yo. تقوم Yo بإنشاء رمز معياري بمساعدة المولدات (التي تعد مجرد قوالب سقالات) وتقوم تلقائيًا بتكوين Grunt و Bower لمشروعك. يمكنك العثور على مولدات لأي إطار عمل JavaScript تقريبًا (Angular ، Backbone ، Ember ، إلخ) ، ولكن نظرًا لأننا نركز هنا على Angular ، فسنستخدم مشروع زاوية المولد.
إذن، أين نبدأ؟
حسنًا ، أول شيء يتعين علينا القيام به هو تثبيت الأدوات التي سنحتاجها.
إذا لم يكن لديك git و node.js و npm مثبتين بالفعل ، فابدأ وقم بتثبيتها.
ثم ننتقل إلى سطر الأوامر ونقوم بتشغيل الأمر التالي لتثبيت أدوات Yeoman:
npm install -g yo grunt-cli bower
أوه ، ولا تنس ، سنستخدم مولد AngularJS ، لذا ستحتاج إلى تثبيته أيضًا:
npm install -g generator-angular
حسنًا ، نحن الآن جاهزون لـ ...
سقالة / إنشاء تطبيق AngularJS الخاص بنا
في المرة الأخيرة ، اقترضنا يدويًا الكود المعياري الخاص بنا من مشروع البذور الزاوية. هذه المرة ، سنسمح لك (بالاشتراك مع المولد الزاوي) بفعل ذلك لنا.
كل ما نحتاج إلى القيام به هو إنشاء مجلد مشروع جديد الخاص بنا ، والانتقال إليه وتشغيل:
yo angular
سنعرض علينا بعض الخيارات ، مثل تضمين Bootstrap و Compass أم لا. في الوقت الحالي ، دعنا نقول لا لـ Compass ونعم لـ Bootstrap. بعد ذلك ، عندما يُطلب منك تحديد الوحدات المراد تضمينها (الموارد وملفات تعريف الارتباط والتعقيم والمسار) ، سنحدد فقط angular-route.js
.
يجب الآن إنشاء سقالة مشروعنا (قد يستغرق الأمر دقيقة) ، ودمجها مع Karma وجميعها مهيأة مسبقًا.
ملاحظة: ضع في اعتبارك أننا نقصر الوحدات النمطية هنا على تلك التي استخدمناها في التطبيق الذي أنشأناه في الجزء الأول من هذا البرنامج التعليمي. عندما تفعل ذلك لمشروعك الخاص ، سيكون عليك تحديد الوحدات التي ستحتاج إلى تضمينها.
الآن ، بما أننا سنستخدم الياسمين ، فلنقم بإضافة محول karma-jasmine
إلى مشروعنا:
npm install karma-jasmine --save-dev
في حالة رغبتنا في تنفيذ اختباراتنا على مثيل Chrome ، فلنضيف أيضًا karma-chrome-launcher
:
npm install karma-chrome-launcher --save-dev
حسنًا ، إذا فعلنا كل شيء بشكل صحيح ، فيجب أن تبدو شجرة ملفات المشروع الآن كما يلي:
ينتقل رمز التطبيق الثابت الخاص بنا إلى app/
الدليل وسيحتوي test/
الدليل (نعم ، لقد خمنت ذلك!) على اختباراتنا. الملفات التي نراها على الجذر هي ملفات تكوين مشروعنا. هناك الكثير لنتعلمه عن كل واحد منهم ، لكن في الوقت الحالي سنلتزم فقط بالتكوين الافتراضي. لذلك دعونا نشغل تطبيقنا لأول مرة ، والذي يمكننا القيام به ببساطة باستخدام الأمر التالي:
grunt serve
وفويلا! يجب أن يظهر تطبيقنا الآن أمامنا!
قليلا عن Bower for AngularJS
قبل الدخول في الجزء المهم حقًا (أي الاختبار) ، دعنا نخصص دقيقة واحدة لمعرفة المزيد عن Bower. كما ذكرنا سابقًا ، Bower هو مدير الحزم لدينا. يمكن ببساطة إضافة lib أو plugin إلى مشروعنا باستخدام أمر bower install
. على سبيل المثال ، لتضمين modernizr
، كل ما نحتاج إليه هو ما يلي (في دليل مشروعنا بالطبع):
bower install modernizr
لاحظ ، بالرغم من ذلك ، أنه على الرغم من أن هذا يجعل modernizr
جزءًا من مشروعنا (سيكون موجودًا في دليل app/bower_components
) ، ما زلنا مسؤولين عن تضمينه في تطبيقنا (أو إدارته عندما يجب تضمينه) كما نحتاج للقيام بأي ليب مضاف يدويًا. تتمثل إحدى طرق القيام بذلك في إضافة علامة <script>
التالية إلى index.html
الخاص بنا:
<script src="bower_components/modernizr/modernizr.js"></script>
بدلاً من ذلك ، يمكننا استخدام ملف bower.json
لإدارة تبعياتنا. بعد اتباع كل خطوة بعناية حتى الآن ، يجب أن يبدو ملف bower.json
كما يلي:
{ "name": "F1FeederApp", "version": "0.0.0", "dependencies": { "angular": "1.2.15", "json3": "~3.2.6", "es5-shim": "~2.1.0", "jquery": "~1.11.0", "bootstrap": "~3.0.3", "angular-route": "1.2.15" }, "devDependencies": { "angular-mocks": "1.2.15", "angular-scenario": "1.2.15" } }
بناء الجملة واضح إلى حد ما ، ولكن يتوفر المزيد من المعلومات هنا.
يمكننا بعد ذلك إضافة أي تبعيات جديدة إضافية نريدها ، وبعد ذلك كل ما نحتاجه هو الأمر التالي لتثبيتها:
bower install
الآن دعنا نكتب بعض الاختبارات!
حسنًا ، حان الوقت الآن للمتابعة من حيث توقفنا في الجزء الأول وكتابة بعض الاختبارات لتطبيق AngularJS الخاص بنا.

لكن أولاً ، هناك مشكلة صغيرة نحتاج إلى معالجتها: على الرغم من أن مطوري المولد الزاوي قد اعتمدوا قالب مشروعهم على مشروع البذور الزاوي (وهو النموذج المعياري الزاوي الرسمي) ، لسبب ما لا أفهمه حقًا ، فقد قرروا لتغيير اصطلاحات تسمية مجلد app
(تغيير css
إلى styles
، و js
إلى scripts
، وما إلى ذلك).
نتيجة لذلك ، يحتوي التطبيق الذي كتبناه في الأصل الآن على مسارات لا تتوافق مع السقالة التي أنشأناها للتو. للتغلب على هذا ، دعنا ننزِّل رمز التطبيق من هنا ونعمل مع هذا الإصدار من هذه النقطة فصاعدًا (غالبًا ما يكون نفس التطبيق الذي كتبناه في الأصل ، ولكن مع تحديث المسارات لتتناسب مع التسمية الزاوية للمولد).
بعد تنزيل التطبيق ، انتقل إلى مجلد tests/spec/controllers
وأنشئ ملفًا باسم drivers.js
يحتوي على ما يلي:
describe('Controller: driversController', function () { // First, we load the app's module beforeEach(module('F1FeederApp')); // Then we create some variables we're going to use var driversController, scope; beforeEach(inject(function ($controller, $rootScope, $httpBackend) { // Here, we create a mock scope variable, to replace the actual $scope variable // the controller would take as parameter scope = $rootScope.$new(); // Then we create an $httpBackend instance. I'll talk about it below. httpMock = $httpBackend; // Here, we set the httpBackend standard reponse to the URL the controller is // supposed to retrieve from the API httpMock.expectJSONP( "http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK").respond( {"MRData": {"StandingsTable": {"StandingsLists" : [{"DriverStandings":[ { "Driver": { "givenName": 'Sebastian', "familyName": 'Vettel' }, "points": "397", "nationality": "German", "Constructors": [ {"name": "Red Bull"} ] }, { "Driver": { "givenName": 'Fernando', "familyName": 'Alonso' }, "points": "242", "nationality": "Spanish", "Constructors": [ {"name": "Ferrari"} ] }, { "Driver": { "givenName": 'Mark', "familyName": 'Webber' }, "points": "199", "nationality": "Australian", "Constructors": [ {"name": "Red Bull"} ] } ]}]}}} ); // Here, we actually initialize our controller, passing our new mock scope as parameter driversController = $controller('driversController', { $scope: scope }); // Then we flush the httpBackend to resolve the fake http call httpMock.flush(); })); // Now, for the actual test, let's check if the driversList is actually retrieving // the mock driver array it('should return a list with three drivers', function () { expect(scope.driversList.length).toBe(3); }); // Let's also make a second test checking if the drivers attributes match against // the expected values it('should retrieve the family names of the drivers', function () { expect(scope.driversList[0].Driver.familyName).toBe("Vettel"); expect(scope.driversList[1].Driver.familyName).toBe("Alonso"); expect(scope.driversList[2].Driver.familyName).toBe("Webber"); }); });
هذه هي مجموعة الاختبار الخاصة driverscontroller
لدينا. قد يبدو الكثير من التعليمات البرمجية ، ولكن معظمها في الواقع مجرد إعلان بيانات وهمية. دعنا نلقي نظرة سريعة على العناصر المهمة حقًا:
- تحدد طريقة description
describe()
مجموعة الاختبار الخاصة بنا. - كل
it()
هو مواصفات اختبار مناسبة. - يتم تنفيذ كل وظيفة
beforeEach()
قبل كل اختبار.
العنصر الأكثر أهمية (وربما المربك) هنا هو خدمة $httpBackend
التي أنشأناها في المتغير httpMock
. تعمل هذه الخدمة كخلفية مزيفة وتستجيب لمكالمات API الخاصة بنا في عمليات التشغيل الاختبارية ، تمامًا كما يفعل خادمنا الفعلي في الإنتاج. في هذه الحالة ، باستخدام وظيفة expectJSONP()
، قمنا بتعيينها لاعتراض أي طلبات JSONP إلى عنوان URL المحدد (نفس العنوان الذي نستخدمه للحصول على المعلومات من الخادم) وبدلاً من ذلك ، نعيد قائمة ثابتة بها ثلاثة محركات ، ومحاكاة استجابة الخادم الحقيقية. يتيح لنا ذلك معرفة ما يفترض أن يعود من وحدة التحكم على وجه اليقين. لذلك يمكننا مقارنة النتائج مع تلك المتوقعة ، باستخدام وظيفة expect()
. إذا تطابقوا ، سينتقل الاختبار.
يتم إجراء الاختبارات ببساطة باستخدام الأمر:
grunt test
يجب أن تكون مجموعة الاختبار لوحدة التحكم في تفاصيل السائق (وحدة التحكم في drivercontroller
) مشابهة إلى حد ما لتلك التي رأيناها للتو. أوصيك بمحاولة اكتشاف ذلك بنفسك على أنه تمرين (أو يمكنك إلقاء نظرة هنا ، إذا لم تكن على استعداد لذلك).
ماذا عن اختبارات AngularJS الشاملة؟
قدم فريق Angular مؤخرًا عداءًا جديدًا للاختبارات الشاملة يسمى منقلة. يستخدم webdriver للتفاعل مع التطبيق الذي يتم تشغيله في المتصفح ويستخدم أيضًا إطار عمل اختبار Jasmine افتراضيًا ، وبالتالي فإن بناء الجملة سيكون متسقًا للغاية مع اختبارات الوحدة الخاصة بنا.
نظرًا لأن منقلة أداة جديدة إلى حد ما ، على الرغم من ذلك ، فإن تكاملها مع مكدس Yeoman ولا يزال generator-angular
يتطلب قدرًا لا بأس به من أعمال التكوين. مع وضع ذلك في الاعتبار ، وأعتزم إبقاء هذا البرنامج التعليمي بسيطًا قدر الإمكان ، فإن خطتي هي تخصيص منشور مستقبلي حصريًا لتغطية الاختبار الشامل في AngularJS بشكل متعمق.
خاتمة
في هذه المرحلة من سلسلة البرامج التعليمية ، تعلمنا كيفية سقالة تطبيق Angular الخاص بنا ، وإدارة protractor
باستخدام yo
، وكتابة / تشغيل بعض الاختبارات باستخدام karma
bower
. ومع ذلك ، ضع في اعتبارك أن هذا البرنامج التعليمي مخصص فقط كمقدمة لأدوات وممارسات AngularJS هذه ؛ لم نحلل أيًا منهم هنا بعمق كبير.
كان هدفنا ببساطة هو مساعدتك على البدء في هذا المسار. من هنا ، الأمر متروك لك للمتابعة وتعلم كل ما تستطيع حول هذا الإطار المذهل ومجموعة الأدوات.
إضافة: بعض الملاحظات (الهامة) من المؤلف
بعد قراءة هذا البرنامج التعليمي ، قد يسأل بعض الأشخاص ، "انتظر. ألا يفترض أن تفعل كل هذه الأشياء قبل أن تبدأ بالفعل في برمجة تطبيقك؟ ألا يجب أن يكون هذا جزءًا من هذا البرنامج التعليمي؟ "
إجابتي القصيرة على ذلك هي لا . كما رأينا في الجزء الأول ، لا تحتاج في الواقع إلى معرفة كل هذه الأشياء لتشفير تطبيق Angular الأول الخاص بك. بدلاً من ذلك ، تم تصميم معظم الأدوات التي ناقشناها في هذا المنشور لمساعدتك على تحسين سير عمل التطوير وممارسة التطوير المستند إلى الاختبار (TDD).
وبالحديث عن TDD ، فإن المفهوم الأساسي لـ TDD هو بالتأكيد مفهوم سليم ؛ أي اكتب الاختبارات قبل كتابة التعليمات البرمجية الخاصة بك. ومع ذلك ، فإن بعض الناس يأخذون هذا المفهوم بعيدًا جدًا. TDD هي ممارسة تنموية وليست طريقة تعلم. وفقًا لذلك ، فإن كتابة الاختبارات قبل كتابة التعليمات البرمجية الخاصة بك أمر منطقي للغاية ، في حين أن تعلم كيفية كتابة الاختبارات قبل تعلم كيفية البرمجة ليس كذلك.
أنا شخصياً أعتقد أن هذا هو السبب الرئيسي الذي يجعل دروس Angular الرسمية تبدو معقدة للغاية ويمكن أن يكون من المستحيل تقريبًا متابعتها للأشخاص الذين ليس لديهم خبرة سابقة في MVC / TDD. هذا هو أحد الأسباب الرئيسية لبدء هذه السلسلة التعليمية.
نصيحتي الشخصية لأولئك الذين يتعلمون الإبحار في عالم AngularJS هي: لا تقسو على نفسك. لست بحاجة إلى تعلم كل شيء دفعة واحدة (على الرغم من أن الناس أخبروك بخلاف ذلك!). اعتمادًا على خبرتك السابقة مع أطر عمل أخرى للواجهة الأمامية / الاختبار ، قد يكون من الصعب جدًا فهم AngularJS في البداية. لذا ، تعلم كل ما تحتاج إلى تعلمه حتى تتمكن من كتابة تطبيقاتك البسيطة ، وبعد ذلك ، بمجرد أن تشعر بالراحة تجاه أساسيات إطار العمل ، يمكنك أن تهتم باختيار وتطبيق ممارسات التطوير طويلة المدى التي تعمل بشكل أفضل من أجل أنت.
بالطبع ، هذا هو رأيي المتواضع ولن يتفق الجميع مع هذا النهج (وقد يرسل فريق Angular dev قاتلًا مأجورًا بعدي بمجرد أن أنشر هذا) ، ولكن هذه هي رؤيتي وأنا متأكد من أن هناك الكثير من الأشخاص هناك من يتفق معي.