Тестування коду javascript. Модульне тестування коду JavaScript: стратегії, бібліотеки, інструменти. Проблеми PhantomJS у Windows

Головна / Усунення несправностей

Створення ефективних тест-кейсів може бути вкрай важливим для великих проектів, якщо поведінка частин програми може змінюватися з різних причин. Мабуть, найчастішою є проблема, коли велика група розробників працюють над тим самим, або суміжними модулями. Це може призвести до незапланованого зміни поведінки функцій, написаних іншими програмістами. Або робота в стислі терміни призводить до ненавмисної зміни критичних частин програми.

Тестування веб-програми зазвичай полягає у візуальній оцінці елементів сторінки та емпіричній оцінці працездатності функціоналу. Тобто в переході по розділах та скоєнні дій над динамічними елементами.

Згодом проект наповнюється новими функціональними можливостями, що подовжує та ускладнює процес перевірки його роботи. Для автоматизації використовують модульне (unit) тестування.

Існують 2 підходи до побудови тестових сценаріїв:

  • WhiteboxTesting– написання тестів ґрунтується на реалізації функціоналу. Тобто. ми перевіряємо за тими самими алгоритмами, у яких будуватися роботи модулів нашої системи. Такий підхід не гарантує коректність роботи системи загалом.
  • BlackboxTesting- Створення сценаріїв базується на специфікаціях та вимогах до системи. Так можна перевірити правильність результатів роботи всієї програми, проте подібний підхід не дозволяє відловити дрібні та рідкісні помилки.

Що тестувати

Може здатися, що варто проводити тести кожну функцію, яку ви реалізували. Це не зовсім так. Написання тестів займає час розробника, для оптимізації процесу роботи над створенням програми варто готувати тести лише складних, критичних, чи тих функцій, які залежить від результатів роботи інших модулів системи. Покривайте тестами неоднозначну логіку, в якій можуть виникати помилки. Також варто створювати тести для тих ділянок коду, які в майбутньому планується оптимізувати, щоб після процесу оптимізації можна було переконатися в коректності їх виконання.

Взагалі дуже важливо оцінювати витрати на проведення тестування щодо стиснення термінів розробки. Звісно, ​​якщо ви не обмежені у часі, то можете дозволити покрити тестами кожну функцію. Але зазвичай розробка ведеться у жорсткому цейтноті, отже завдання аналітика чи досвідченого розробника зрозуміти, де проведення тестування необхідно. Крім того, написання тестів підвищує вартість проекту.

Таким чином можна сформулювати 3 випадки, коли використання модульного тестування виправдане:

1) Якщо тести дають можливість швидше виявити помилки, ніж за звичайного їх пошуку.

2) Знижують час на налагодження

3) Дозволяють тестувати код, що часто змінюється.

З трьох основних компонент фронтенду (HTML, CSS, JavaScript) тестувати потрібно, мабуть лише JavaScript-код. CSS перевіряється виключно візуальним методом, коли розробник/тестувальник/замовник переглядає графічний інтерфейсв різних браузерах. HTML – розмітка перевіряється тим самим способом.

Як тестувати

При побудові сценаріїв проведення тестів слід керуватися такими принципами:

  • Ваші тести мають бути максимально простими.Тоді буде більша ймовірність того, що на результати його проведення впливатиме саме той баг, який ви намагаєтеся повторити.
  • Декомпозируйте тести великих модулів.Найчастіше знайти конкретне місце помилки.
  • Робіть тести незалежними.Результат одного тесту в жодному разі не повинен залежати від результатів іншого.
  • Результати проведення тестів мають бути повністю повторюваними та очікуваними.Щоразу, коли ви знову запускаєте тест, його результат має бути тим самим, що й минулого разу.
  • Для будь-якої помилки у виконанні програми має бути створений сценарій тестування.Таким чином, ви будете впевнені, що баг дійсно виправлений і не проявляється у користувачів.

Чим тестувати

Для unit-тестування js-коду є кілька бібліотек. Мабуть найпоширенішою є QUnit. Для проведення модульних тестів за допомогою цієї бібліотеки нам потрібно створити «пісочницю» — просту html-сторінку, в якій будуть підключені бібліотека для тестування, код, який потрібно тестувати, і власне самі тести.

Функції для тестів:

(function() ( window.stepen = function(int) ( var result = 2; for (var i = 1; i)< int; i ++) { result = result * 2; } return result; } window.returnFunc = function() { return "ok"; } })();

Лістинг тестів:

Test("stepen()", function() ( equal(stepen(2), 4, "2^2 - equal method"); ok(stepen(3) === 8, "2^3 - ok method" );deepEqual(stepen(5), 32, "2^5 - deepEqual method"); )); asyncTest("returnFunc()", function() ( setTimeout(function() ( equal(returnFunc(), "ok", "Async Func Test"); start(); ), 1000); ));

Як видно, QUnit підтримує 3 функції для порівняння результатів виконання коду з очікуваним:

  • ok()– вважає тест успішним, якщо результат, що повертається = true
  • equal()- Порівнює результат з очікуваним
  • deepEqual()- Порівнює результат з очікуваним, перевіряючи його тип

Результат виконання:

Як видно, бібліотека QUnit проводить тестування коду одразу для кількох браузерів.

Існує низка інших бібліотек для модульних тестів. Однак концепція побудови сценаріїв тестування в них та сама, так що розібравшись з однієї – у вас не важко перейти на іншу.

Важливо пам'ятати

Особливістю сучасного js-коду є асинхронність його виконання. Бібліотеки для тестування зазвичай мають можливість проведення асинхронних тестів. Але наприклад якщо ви намагаєтеся протестувати функцію, яка, скажімо, посилає get-запит на бекенд і повертає відповідь від нього, то для проведення тестів доведеться зупиняти потік функцією stop(), запускати функцію, що тестується, а потім заново запускати потік методом start() , «Обернувши його» в setTimeout(). Тобто. ви повинні закласти якийсь проміжок часу, протягом якого має завершитися виконання функції. Потрібно старанно вибирає тривалість цього відрізка, .к. з одного боку тривала робота методу то, можливо як особливість і навіть необхідністю конкретної реалізації функціоналу докладання, і некоректним поведінкою.

Тестування Backbone додатків

Для прикладу тестування додатків, написаних з використанням Backbone.js, скористаємося проектом, описаним у .

Модульними тестами можна перевірити:

  • Коректність створення моделей та контролерів
  • Правильність даних у моделях
  • Виконання методів контролерів (для цього вони мають повертати результат)
  • Успішність завантаження уявлень

Код тестів:

Test("Backbone.js", function() ( ok(sample, "Namespace check"); ok(sample.routers.app, "Router check")); ok(sample.core.pageManager.open("chat") , "Page opening test (Controller method call)") ok(sample.core.state, "Model check"); "); html(data); return data; )) ), "Template loading check");

Результат роботи з помилками тестування:

Автоматизація запуску тестів

Як правило, розгортання програми є завданням, яке доводиться виконувати досить часто при інтенсивній розробці. Тому цю операцію зазвичай автоматизують. Ми використовуємо Jenkins – інструмент для безперервної інтеграції. Ідея полягає у поєднанні деплою через Jenkins із проведенням автоматичних тестів.

QUnit тести запускаються у браузері. Обійти цю особливість нам допоможе phantomjs - ПЗ, що емулює роботу браузера. Розробники phantomjs вже надали скрипт для виконання QUnit тестів, проте для коректної роботи довелося трохи його доопрацювати.

/** * Відсутність тесту умови є true або timeout occurs. * Useful for waiting * on a server response або for ui change (fadeIn, etc.) to occur. * * @param testFx javascript condition that evaluates to a boolean, * it can be passed in as string (e.g.: "1 == 1" or * "$("#bar").is(":visible")" or * as a callback function. (":visible")" or * as a callback function. * @param timeOutMillis max amount of time to wait. If not * specified, 3 sec is used. = timeOutMillis ?timeOutMillis: 3001, //< Default Max Timout is 3s start = new Date().getTime(), condition = false, interval = setInterval(function() { if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) { // If not time-out yet and condition not yet fulfilled condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code } else { if(!condition) { // If condition still not fulfilled // (timeout but condition is "false") console.log(""waitFor()" timeout"); phantom.exit(1); } else { // Condition fulfilled (timeout and/or condition is //"true") console.log(""waitFor()" finished in " + (new Date().getTime() - start) + "ms."); typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it"s supposed to do once the // condition is fulfilled clearInterval(interval); //< Stop this interval } } }, 100); // repeat check every 250ms }; }; if (phantom.args.length === 0 || phantom.args.length >2) console.log("Usage: run-qunit.js URL"); phantom.exit(); ) var page = новий WebPage(); // Route "console.log()" calls from in the Page // context to the main Phantom context (i.e. current "this") page.onConsoleMessage = function(msg) ( console.log(msg); ); page.open(phantom.args, function(status)( if (status !== "success") ( console.log("Unable to access network"); phantom.exit(); ) else ( waitFor(function() ( return page.evaluate(function()( var el = document.getElementById("qunit-testresult"); if (el && el.innerText.match("completed")) ( return true; ) return false; )); ), function()( var failedNum = page.evaluate(function()( var el = document.getElementById("qunit-testresult"); console.log(el.innerText); try ( return document.getElementsByClassName("fail") ).innerHTML.length; ) catch (e) ( return 0; ) return 10000; ));phantom.exit((parseInt(failedNum, 10) > 0) ? 1: 0);

Для виведення в консоль повідомлень про результати у скрипт із тестами потрібно додати функцію логування.

Тестування коду- Невід'ємний цикл розробки програмного забезпечення. Початківці девелоперів часто недооцінюють його роль і перевіряють працездатність програми по-старому – «працює, та й добре». Рано чи пізно ця стратегія дає збій і баг-трекер починає захльостувати незліченну армію тяган. Щоб не потрапити в таку пастку, рекомендую раз і назавжди розібратися з нюансами тестування JavaScriptкоду.

JavaScript вже не той

Сьогодні JavaScript– це не просто мова для пожвавлення зовнішнього виглядупрограми. Часи, коли JavaScript використовували для жартів або виготовлення меню безповоротно пройшли. Тепер це самостійна мова, яка однаково добре працює як на клієнті, так і на сервері. Роль JavaScript істотно підвищилася, а значить, при написанні коду потрібно не соромитися користуватися практиками, що добре зарекомендували себе в інших мовах програмування.

Що я маю на увазі під практиками та парадигмами? Звичайно ж, архітектурний шаблон MVC (model view controller)та патерни організації коду. Слідуючи цим не хитрим премудростям, ти зможеш писати якісніший код, який буде не тільки легко супроводжуватися, але мати здатність до автоматичного тестування.

Помилка більшості тестерів

Ні для кого не секрет, що найпопулярнішим способом тестування завжди була банальна перевірка на «око». Його суть проста до неподобства - написав кілька тисяч рядків коду, вирішив завдання і запускаєш свій витвір. Погрався, покликав – начебто все працює, можна заливати на бойовий сервер. Все гранично просто і при належній увазі розробника (в ідеалі окремої людини на прізвисько «тестер») можна покластися на коректність роботи програми.

На практиці все відбувається дещо інакше. Окремого тестувальника зазвичай немає. Розробник сам намагається перевірити працездатність програми, виконуючи певну у технічному завданні послідовність дій. Більш просунуті кузні коду автоматизують подібне інтеграційне тестування за допомогою речей на кшталт Selenium.

Таким чином, програміст отримує можливість виявити лише грубі помилки. На жаль, «тупі» і «непередбачені» дії користувача, а також хитрі ходи в бізнес-логіці, в 99% випадків залишаються за кадром.

Наявність окремої людини в особі тестувальника вирішує проблему також частково і до певного часу. Навіть якщо відкинути його саперську увагу до деталей, то якість його тестування буде прагнути до нуля зі зростанням додатка. Наведу приклад із практики.

Якось мені доручили розробити невелику програмку. За функціонал проект нагадував найпростішу CRM, яку я й реалізував у найкоротший термін. Отримавши належну винагороду, я передав усі вихідники замовнику і на вісім місяців забув про проект. Далі почалося найцікавіше. Замовник вирішив серйозно розширити функціонал програми та закликав мене на допомогу. Природно я взявся і почав робити нову функцію за функцією. Спочатку це було не складно, але коли дійшло справу до загальної інтеграції функціоналу, дзижчий рій багів кинувся в мій бік. Шматки коду почали конфліктувати, і доводилося витрачати багато часу на розрулювання конфліктів. «А як же ти не бачив, що з твоїм додатком проблеми?» - Запитають уважні читачі. Запускав, але через те, що додаток розрісся мені банально не вистачало часу і нервів протестувати весь функціонал скопом. Я обмежувався тестом лише окремих функцій та щедро поплатився за це. Мораль цієї байки – «Думай про тестування як невід'ємну частину розробки».

Unit тести як срібна куля

Уберегти свої нерви та підвищити гарантії працездатності окремих частин програми найкраще допомагає модульне тестування. Якщо ти ще жодного разу не стикався із цим страшним словом, то поясню коротко. Модульні тести дозволяють автоматизувати процес тестування та піддати тестам кожну функцію програми.

Після завершення розробки нової функції (можливий варіант написання тестів до початку розробки) девелопер пише спеціальний код для тестування свого коду. У коді для тестування потрібно зімітувати різні ситуації та значення, що повертаються. Наприклад, ми написали функцію для усічення прогалин (trim). Щоб протестувати її працездатність, ми повинні підготувати кілька тестів, які дозволять стверджувати, що:

  • при передачі рядка "рядок" на виході ми отримаємо "рядок";
  • при передачі терміни "рядок 9" на виході ми отримаємо "рядок 9";
  • Ми також можемо додати тестування на інші вхідні параметри (наприклад, замінити символ пробілу на табуляцію). Загалом, чим краще ми покриємо код тестами, і передбачимо можливих негативних варіантів, тим більше шансів, що найвідповідальніший момент на голові залишиться трішки волосся.

    У світі JS тести зазвичай описуються за допомогою спеціалізованих фреймворків. У них є все необхідне для опису тестів, а також худорляві інструменти для систематизації звітів про хід тестування.

    Тести! = зайвий код

    Розробники, які не використовують unit-тестування, люблять стверджувати, що модульне тестування вимагає написання та підтримки додаткового коду. Мовляв, терміни у реальних проектах найчастіше стислі та писати додатковий код просто немає можливості.

    На рахунок стислих термінів я погоджуся, а от щодо зайвого коду готовий посперечатися. З одного боку, так, тести вимагають додаткового коду, а отже, і часу на його написання. З іншого боку, цей код виконує роль подушок безпеки в автомобілі та обов'язково окупиться зі зростанням програми.

    Коли немає часу і мучить бажання відмовитись від написання тестів – тричі подумай. Може в такому разі доречніше покрити тестами лише найхитріші ділянки коду, а не відмовлятися від тестування повністю. Завжди думай із прицілом на майбутнє, ніби за місяць твоя програма може розростити до небувалих розмірів.

    Не всякий код тестується

    Чому я стверджую, що замислюватись про тестування потрібно до написання основного коду? Тому, що код, який спочатку передбачається покривати unit-тестам, пишеться в дещо іншому стилі. Не всякий код можна протестувати. Код, в якому поєднується логіка та уявлення, та ще й розпханий де неможливо нормально протестувати. Тут я завжди раджу дотримуватись кількох простих правил:

  • Не слід писати великих функцій. Кожна функція повинна вирішувати одну проблему, а не 100 500 можливих ситуацій. Наприклад, не потрібно вішати код відправлення даних на сервер у функцію, що відповідає за їхню підготовку;
  • Функція, що складається з понад 10 рядків коду швидше за все погана функція;
  • Логіка та уявлення в жодному разі не повинні бути разом;
  • QUnit – класика жанру від творців jQuery

    QUnitкористується особливою популярністю серед розробників JavaScript. По-перше, вона добре документована і проста у використанні, а по-друге вона створена авторами jQuery. Бібліотека підходить як для тестування коду, створеного на базі jQuery, так і JavaScript.

    Завантажити останню версію QUnit ти можеш з офіційного сайту - http://qunitjs.com/. Бібліотека постачається у вигляді одного JS та CSS файлу. Припустимо, що із завантаженням необхідних компонентів ти розібрався, а раз так, то саме час написати пробний тест. Не будемо далеко ходити і спробуємо протестувати вищезгадану функцію trim().

    Для демонстрації тестів я створив найпростіший проект із наступною структорою:

    Index.html – основний файл, який відображатиме результати тестів; - qunit-1.12.0.js – файл бібліотеки qunit; - example.js – файл, що містить код для тестування (у разі опис функції trim()); - test.js – файл із тестами; - qunit-1.12.0.css – стилі для оформлення звіту із тестами;

    Вміст файлу index.html і test.js представлений у лістингу 1 і 2. Найбільше нас цікавить другий лістинг, в якому наведено оголошення функції, що тестується (trim()) і код тестів для перевірки її працездатності. Зверніть увагу, сама функція trim() може розташовуватися будь-де, я її засунув у другий лістинг тільки задля економії місця в журналі.

    Тепер подивимося самі тести. Для здійснення перевірок працездатності нашого коду Qunit.jsпропонує нам низку методів:

  • test()- Обгортка для опису тесту;
  • ok()- Затвердження дозволяє перевірити істинність першого параметра. У нашому прикладі я передаю їй виклик певної функції trim() і порівнянню зі значенням, яке я чекаю отримати. Якщо умова істинна – тест пройдено;
  • equal()– метод дозволяє перевірити рівність першого та другого параметра. Відразу зверни увагу, що даний методвиконує нестрогу перевірку, тому годиться лише скалярних величин;
  • notEqual()- Протилежний equal (). Виконується, якщо перше значення, не дорівнює другому;
  • strictEqual()–аналогічний equal() з однією лише відмінністю – він використовує строгу перевірку (тобто. перевіряє ще й тип даних);
  • notStrictEqual()– метод протилежний strictEqual();
  • deepEqual()– метод для рекурсивних тверджень, що застосовується для примітивів, масивів, об'єктів;
  • notDeepEqual()– метод протилежний deepEqual();
  • raises()- Затвердження для тестування функцій зворотного виклику, що генерують виняток;
  • У другому лістингу я наочно показав, як застосовувати ці методи практично. Якщо запустити тестовий приклад у такому вигляді, всі тести будуть успішно пройдені (див. відповідний малюнок). Щоб побачити різницю між успішно пройденими тестами і завершимося з помилками, я трохи змінив код одного тесту. У рядок із тестом за допомогою strictEqual()я додав помилковий результат (див. відповідний малюнок).

    Лістинг 1. Вміст файлу index.html

    Тестування за допомогою QUnit

    Лістинг 2. Файли тестів та функція trim()

    function trim(string) ( return (string || "").replace(/^\s+|\s+$/g, ""); ) test("Тест функції trim()", function() ( ok(trim ("test") == "test", "обрізаємо крайні прогалини"); ok(trim("1") == "1", "дуже багато пробілів з боків"); = "24", "пробіли та таби з боків"); equal(trim(""), "", "Порожній рядок");

    З тестуванням простих функційначебто розібралися. Принаймні мені додати більше нічого. Далі треба брати реальний код та пробувати писати тести самостійно. Подивимося на інше, часто виникає завдання перед JavaScript-Розробниками - тестування асинхронних функцій. Програма, напхана JavaScript-кодом, в 99% взаємодіє з серверною частиною за допомогою Ajax. Залишати цей код без перевірки також не можна, але написання тестів виглядатиме трохи інакше. Розглянемо приклад:

    AsyncTest("myAsyncFunc()", function() ( setTimeout(function() ( ok(myAsyncFunc() == true, "Дані успішно передані"); start(); ), 500); ));

    Головна відмінність цього прикладу від попереднього – замість обгортки test() застосовується asyncTest(), тим самим заявляючи, що мене цікавить тестування саме асинхронне тестування. Далі я запускаю час очікування 500 мл. сек. За цей час функція myAsyncFunc() повинна передати дані на тестовий сервер, і якщо все повернути true. Ось тут настає самий цікавий момент. Коли відбувається виклик asyncTest(), потік виконання зупиняється і після закінчення тесту його необхідно самостійно запустити. Для управління потоком виконання QUnitє методи start() та stop().

    Тестування асинхронних функцій за допомогою бібліотеки QUnitвиконується досить легко. Останній приклад, який мені хотілося б розібрати, пов'язаний із написанням тесту, який виконує кілька асинхронних перевірок. Головне питання, яке виникає на цьому у подібних завданнях, – оптимальне місце для старту потоку виконання. Офіційний док пропонує застосовувати у таких випадках щось на зразок:

    AsyncTest("myAsyncFunc()", function() ( expect(3); //Тут робимо три перевірки ok(myAsyncFunc(), "Робимо світ краще 1"); ok(myAsyncFunc(), "Робимо світ краще 2")) ok(myAsyncFunc(), "Робимо світ краще 3"); setTimeout(function() ( start(); ), 3000); ));

    Тест для дій користувача

    Завжди треба пам'ятати, що JavaScript пишеться дуже багато всяких інтерфейсних штук. Наприклад, користувач кликає по пімпі і у відповідь на його клік має щось статися. Подібного «інтерфейсного» коду в проектах дуже багато і його також потрібно покривати тестами. Давай подивимося, як можна змоделювати натискання клавіші і написати для цього дії окремий тест. Уявімо, що ми маємо якусь функцію, яка логує натиснені клавіші. Її код я навів у третьому лістингу:

    Лістинг 3. Логування натиснутих клавіш

    function KeyLogger(target) ( if (!(this instanceof KeyLogger)) ( return new KeyLogger(target); ) this.target = target; this.log = ; var self = this; this.target.off("keydown") .on("keydown", function(event) ( self.log.push(event.keyCode); )); )

    Тепер спробуємо цю функцію протестувати. Насамперед, у тілі тесту нам необхідно емулювати натиснуту клавішу. Найпростіше це зробити за допомогою бібліотеки jQuery, яка дозволяє створити подію в кілька рядків коду (див. листинг 4).

    Лістинг 4. Код тесту для KeyLogger

    test("Тест запису клавіш", function() ( var event, $doc = $(document), keys = KeyLogger($doc); event = $.Event("keydown"); event.keyCode = 9; $doc .trigger(event);equal(keys.log.length, 1, "Клавіша записана");

    На початку листингу з тестом я готую подію для емуляції натискання клавіші – «keydown». Нас цікавитиме натискання клавіші Tab (код 9). Потім за допомогою методу trigger() я відправляю приготовану подію, після чого можна приступати до тестування. Спочатку перевіряємо загальну картину – чи була натиснута клавіша, а потім її код.

    DOM під прикриттям тестів

    Раз Qunit.jsдозволяє тестувати дії користувача, то з написанням тестів для DOM теж не повинно бути проблем. Це справді так і наведений приклад нижче підтвердить мої слова. Я не коментуватиму його, просто поглянь на код і все стане зрозумілим:

    Test("Додаємо новий елемент div", function() ( var $fixture = $("#qunit-fixture"); $fixture.append("

    Це новий див
    "); equal($("div", $fixture).length, 1, "Новий div успішно доданий!"); ));

    Phantom.JS – запускаємо тести з консолі

    Писати тести за допомогою бібліотеки Qunit.jsзручно і просто, але рано чи пізно її тебе відвідає бажання якось автоматизувати запуск тестування та збирання результатів. Наприклад, у мене для цієї справи є окрема віртуальна машинав DigitalOcean, керувати якою я можу лише за допомогою консолі.

    Досить елегантно цю проблему дозволяє вирішити проект phantom.js. Це не черговий фреймворк для написання Unit-тестів, а повноцінна консольна версія движка WebKit. Якщо сказати простіше, то ця програма емулює браузер. За допомогою phantom.js реально не просто автоматизувати перевірку виконання тестів, але й вирішити безліч завдань, які рано чи пізно виникають перед розробником: отримання результатів рендінгу сторінок у файл (png, jpg), функції мережевого монітора (швидкість завантаження, загальна продуктивність тощо). д.), емуляція дій користувача тощо. Рекомендую не полінуватися і почитати офіційну документацію щодо цього проекту, обов'язково знайдеш щось цікаве для себе.

    Phantom.jsможна зібрати під різні платформи (nix, mac OS X, windows). Якщо ти все розробляєш під Windows, то немає жодних проблем – зливай бінарники й уперед. Невеликі проблеми із запуском можуть виникнути, якщо в тебе встановлено два відеоадаптери, один з яких NVidia. В цьому випадку тобі доведеться скористатися хаком, описаним у врізанні.

    Спробуємо познайомитись з phantom.js на практиці. Щоб пропустити через phantom.jsтести, підготовлені в минулому розділі та отримати результати виконання в консоль, нам знадобиться спеціальний сценарій-лоадер – run-qunit.js . Відкриваємо консоль (я працюю у Windows, тому використовую cmd) та набиваємо команду у форматі:

    Phantom.exe<путь к run-qunit.js> <путь к странице с тестами>

    У моєму випадку команда запуску вийшла такою:

    E:\soft\phantomjs>phantomjs.exe E:\temp\testjsforx\qunit\run-qunit.js file:///E: /temp/testjsforx/qunit/index.html Результат її виконання: Tests completed in 2592 milliseconds . 9 оцінок з 9 пройшли, 0 failed.

    All tests passed

    Покривати код тестами однозначно потрібно і не важливо, якого масштабу програму ти створюєш. Вкотре нагадую, навіть найменші програми перетворюються на неповоротких монстрів, яких необхідно підтримувати та допилювати функціонал. Добре покритий тестами коду – запорука успіху та якості. Так, ось так відразу почати писати придатний для автоматизованих тестів код непросто, але повір, всі ці муки з лишком окупляться в майбутньому. На цьому у мене на сьогодні все, удачі!

    Коли на тести немає часу

    За відсутності часу немає сенсу писати тести для простих функцій (взяти той же trim() з прикладів у статті), краще зосередити на найбільш критичних ділянках коду. Дотримуватися цього правила слід при написанні коду, що часто змінюється. Технічне завдання живого проекту часто змінюється, і деякі функції доводиться постійно оновлювати. Такі зміни можуть спричинити неприємні моменти – з новими даними змінений код працює добре, а старі органічно не перетравлює. Ось щоб не зловити тут фейл, подібні функції краще одразу покрити тестами. Запам'ятай просте правило - немає часу покрити весь код тестами, покрий найважливішу його частину.

    Правила добрих тестів

  • Тест має бути максимально простим. Чим складніший тест, тим більша ймовірність припуститися в ньому помилок;
  • Тести необхідно групувати на модулі, щоб потім було простіше знайти помилки та мати можливість тестувати певні частини програми;
  • Кожен тест ні залежати від інших тестів;
  • Завжди пиши окремий тест при кожному виявленні багів;
  • Проблеми phantom.js у Windows

    Так уже вийшло, але всі приклади до цієї статті я тестував не в Linux, а під старим-добрим Windows 7. Виявляється, phantom.js має невеликі проблеми при роботі на системах, в яких використовується кілька відеоадаптерів. На моєму ноутбуці, крім інтегрованого відео чіпа, ще тусується NVidia і через phantom.js категорично відмовлявся реагувати на команду phantom.exit(). В результаті після виконання сценарію процес phantom.js не завершував свою роботу і продовжував висіти в пам'яті. Вікно терміналу також припиняло реагувати на команди завершення (ctrl + c – не допомагав).

    Якщо ти зіткнувся з подібною проблемою і плануєш використати phantom.jsна Windows, то приготуйся зробити наступний хак. Відкрий панель керування Nvidia. Знайди в дереві пункт "Параметри 3D". З правого боку має з'явитися опція «Переважний графічний адаптер». За замовчуванням її значення встановлено у «Автовиборі». Нам треба її поміняти на Високопродуктивний процесор Nvidia або Інтегроване графічне обладнання. Після цього нехитрого трюку phantom.jsпочав поводитися слухняно.

  • Cristian Johansen Test-Driven JavaScript Development – ​​одна з небагатьох книг, що розглядають JavaScript з точки зору написання тестів;
  • Джон Резінг, Беер Бібо «Секрети JavaScript ніндзя» – гарна книга, яка стане в нагоді в першу чергу JS розробникам із середнім рівнем підготовки. У книзі детально розглядаються питання написання ефективного крос-браузерного коду, нюанси обробки подій та багато інших смакот.
  • Тепер на сайті доступне тестування на знання наступних тем: HTML, CSS, JavaScript, PHP, SQL.

    Кожен тест складається з 10-типитань щодо певної теми. Я намагався в кожному питанні торкатися найрізноманітніших сфер застосування конкретної мови, щоб максимально ретельно перевірити Ваш рівень знань.

    Безумовно, все тести безкоштовніі пройти їх може будь-хто.

    Порядок проходження тесту:

    1. Перейдіть за посиланням Розпочати тестуванняу відповідного тесту.
    2. Відповідаєте на поставлені запитання, обравши єдинийправильний варіант.
    3. Після завершення тестування Ви побачите свій бал, кількість помилок, а також розбір кожного питанняіз тіста.

    Увага!Повернутися до попереднього питання не вийде, тож перш ніж відповідати, думайте.

    Доступні на даний момент тести

    1. HTML

      • Усього тест пройшло: 75424 особи
      • Середній бал: 2.83 із 5балів.

      Тест на знання основ HTML. Від Вас знадобиться знання основних HTML-тегів, і навіть грамотне їх використання. Також необхідно розуміння особливостей стандарту XHTML 1.1.

    2. CSS

      • Усього тест пройшло: 32828 осіб
      • Середній бал: 3.37 із 5балів.

      Тест перевіряє знання з основ CSS. Для успішного проходження тесту Ви повинні знати основні види селекторів (їх синтаксис), знати основні властивості та їх можливі значення, а також знати призначення найпопулярніших псевдоелементів.

    3. JavaScript

      • Усього тест пройшло: 24845 осіб
      • Середній бал: 3.31 із 5балів.

      Цей тест перевіряє Ваші знання з мови JavaScript. Питання з тесту торкаються різних сфер застосування цієї мови. Дуже багато питань є на розуміння "дрібних" нюансів. В іншому ж від Вас потрібне знання базових речей: робота зі змінними, основні функції JavaScript, пріоритети операцій та інше.

    4. PHP

      • Усього тест пройшло: 33239 осіб
      • Середній бал: 3.03 із 5балів.

      Цей тест перевіряє Ваші знання з мови PHP. Від Вас потрібне знання основних конструкцій PHP, роботи зі змінними, сесій, реалізації редиректу та інших стандартних речей
      Переконливе прохання:У тесті міститься багато запитань на кшталт: "Що виведе скрипт?". Велике прохання, не треба копіювати його та перевіряти. Будьте чесні перед собою.

    5. SQL

      • Усього тест пройшло: 18014 осіб
      • Середній бал: 3.28 із 5балів.

      Цей тест перевіряє Ваші знання з мови запитів SQL. Запитання торкаються лише самих базові знанняцієї мови, без будь-якого поглиблення. Від Вас знадобиться найголовніших SQL-запитів, а також грамотне їх використання.

    І є офіційним інструментом тестування jQuery. Але QUnit відмінно підходить для тестування будь-якого коду JavaScript і навіть здатна тестувати серверну частину JavaScript за допомогою механізмів типу Rhino або V8.

    Якщо ви не знайомі з ідеєю "модульного тестування", не засмучуйтесь - у ній немає нічого складного для розуміння:

    "Модульне тестуванняабо юніт-тестування(англ. unit testing) - процес у програмуванні, що дозволяє перевірити на коректність окремі модулівихідний код програми. Ідея полягає в тому, щоб писати тести для кожної нетривіальної функції чи методу. Це дозволяє досить швидко перевірити, чи не призвела чергова зміна коду до регресії, тобто до появи помилок у вже відтестованих місцях програми, а також полегшує виявлення та усунення таких помилок."

    Визначення процитовано з Вікіпедії. Просто зробіть тести для кожного функціонального блоку вашого коду, і якщо всі тести будуть пройдені, можна бути впевненим у відсутності помилок (головним чином залежить від того, наскільки ретельно розроблені тести).

    Навіщо слід тестувати свій код

    Якщо ви ніколи не писали модульних тестів раніше, то, ймовірно, просто розміщували свій код відразу на веб-сервері, запускали його, стежили за виявом помилок і намагалися усунути їх у міру виявлення. Такий метод роботи породжує багато проблем.

    По-перше, це дуже нудне та нудне заняття. Перевірка насправді є дуже складною роботою, бо треба бути впевненим, що все було натиснуто. А в цьому процесі є дуже велика ймовірність, що один-два моменти можуть бути пропущені.

    По-друге, все, що робиться для такого тестування не може бути використане повторно. За такого методу дуже складно знайти регресії. Що таке регресії? Уявіть, що ви написали якийсь код і протестували його, виправили всі помилки, які знайшли, та помістили код на сайті. Потім користувач надіслав відгук про нові помилки та запит на нові функції. Ви повертаєтеся до коду, виправляєте помилки та додаєте нові функції. При цьому може виникнути ситуація, коли старі помилки виявляються знову, що називається "регресією". Вам знову доводиться все перевіряти. І є шанс, що ви не знайдете своїх старих помилок. У будь-якому випадку мине час, перш ніж ви здогадаєтеся, що проблема викликана "регресією". Під час використання модульного тестування ви пишите тест. Як тільки код модифікується, ви знову фільтруєте його через тест. Якщо регресія проявляється, то якісь тести не пройдуть, і ви легко визначите, яка частина коду містить помилку. Оскільки ви знаєте, що змінили, то помилку буде легко виправити.

    Іншою перевагою модульного тестування (особливо для веб-розробок) є те, що легко протестувати крос-браузерну сумісність. Потрібно просто запустити тести у різних браузерах. Якщо виявляться проблеми в браузері, ви зможете виправити їх і запустити тест знову. У результаті ви будете впевнені, що всі цільові браузери підтримуються, оскільки всі вони пройшли тестування.

    Як писати тести модулів у QUnit

    Отже, як безпосередньо писати тести модулів в QUnit? Першим кроком необхідно встановити середовище тестування:

    Комплект для тестів QUnit

    Комплект для тестів QUnit

    Код, який тестуватиметься, міститься у файлі myProject.js, а тести поміщаються в myTests.js. Щоб запустити тести, потрібно просто відкрити HTML файл у браузері. Тепер настав час написати якийсь тест.

    Будівельним блоком модульного тестування є затвердження.

    "Твердження - це вираз, який прогнозує результат, що повертається при виконанні вашого коду. Якщо прогноз невірний, то твердження має значення false, що дозволяє зробити висновки про наявність помилок."

    Для виконання тверджень їх потрібно помістити до блоку тесту:

    // протестуємо цю функцію function isEven(val) ( return val % 2 === 0; ) test("isEven()", function() ( ok(isEven(0), "Нуль - парне число"); ok( isEven(2), "Два - теж"); ok(isEven(-4), "І негативне чотири - теж парне число"); ok(!isEven(1), "Один - непарне число");ok(! isEven(-7), "Як і негативне сім - непарне число"); ))

    Тут ми визначаємо функцію isEven, яка перевіряє парність числа, і хочемо переконатися, що ця функція не повертає помилкових значень.

    Спочатку ми викликаємо функцію test()яка будує блок тесту. Перший параметр є рядком, який виводитиметься в результаті. Другий параметр – зворотна функція, яка містить наші твердження. Ця функція буде викликатися один раз при виконанні QUnit.

    Ми написали п'ять тверджень, усі є логічними. Логічне твердження передбачає, що перший параметр має значення true. Другий параметр – це повідомлення, яке виводиться у результат.

    Ось що ми отримаємо після виконання тесту:

    Всі наші твердження успішно підтвердилися, тому можна вважати, що функція isEven()працює так, як очікувалося.

    Давайте подивимося, що станеться, якщо твердження буде неправильним.

    // протестуємо цю функцію function isEven(val) ( return val % 2 === 0; ) test("isEven()", function() ( ok(isEven(0), "Нуль - парне число"); ok( isEven(2), "Два - теж"); ok(isEven(-4), "І негативне чотири - теж парне число"); ok(!isEven(1), "Один - непарне число");ok(! isEven(-7), "Як і негативне сім - непарне число");// Помилка ok(isEven(3), "Три - парне число"); ))

    І ось що ми отримаємо в результаті виконання тесту:


    Твердження має помилку, яку ми припустилися навмисно. Але у вашому проекті, якщо якийсь тест не проходить, а решта всіх тверджень правильні, то буде дуже легко виявити помилку.

    Інші твердження

    ok() не є єдиним твердженням, яке підтримує QUnit. Існують інші типи тверджень, які зручно використовувати при складанні тестів для ваших проектів:

    Затвердження порівняння

    Затвердження порівняння equals()передбачає, що перший параметр (який є дійсним значенням) еквівалентний другому параметру (який є очікуваним значенням). Це твердження дуже схоже на ok()Але виводить обидва значення - дійсне і передбачуване, що суттєво полегшує налагодження коду. Так само як і ok(), equals()як третій параметр може приймати повідомлення для виведення.

    Так замість

    Test("assertions", function() ( ok(1 == 1, "один еквівалентно одному"); ))


    Слід використовувати:

    Test("assertions", function() ( equals(1, 1, "один еквівалентно одному"); ))


    Зверніть увагу, що наприкінці рядка виводиться передбачуване значення.

    А якщо значення не рівні:

    Test("assertions", function() ( equals(2, 1, "один еквівалентно одному"); ))


    Такий запис дає більше інформації.

    Затвердження порівняння використовує оператор “==” для перевірки параметрів, тому воно може працювати з масивами чи об'єктами:

    Test("test", function() ( equals((), (), "помилка, це різні об'єкти"); equals((a: 1), (a: 1) , "помилка"); equals(, , "помилка, це різні масиви");equals(, , "помилка");

    Для таких випадків у QUnit є затвердження ідентичності.

    Твердження ідентичності

    Твердження ідентичності same()використовує ті ж параметри, що і equals(), але працює не лише з примітивними типами, а й з масивами та об'єктами. Затвердження з попереднього прикладу пройдуть перевірку, якщо змінити затвердження ідентичності:

    Test("test", function() ( same((), (), "проходить, об'єкти мають однаковий контент"); same((a: 1), (a: 1) , "проходить"); same(, , "проходить, масиви мають однаковий контент"); same(, , "проходить"); ))

    Зауважте, що same()використовує оператор '===' для порівняння, тому його зручно використовувати для порівняння спеціальних значень:

    Test("test", function() ( equals(0, false, "true"); same(0, false, "false"); equals(null, undefined, "true")); same(null, undefined, " false"); ))

    Структура тверджень

    Розміщувати всі твердження в одному тесті – дуже погана ідея. Такий тест буде важко підтримувати і можна заплутатися в оцінці результатів його виконання. Тому необхідно структурувати тест, розміщуючи твердження окремі блоки, кожен із яких буде націлений певну групу функций.

    Можна організовувати окремі модулі за допомогою функції module:

    Module("Модуль A"); test("Тест", function() ()); test("Ще один тест", function() ()); module("Модуль B"); test("Тест", function() ()); test("Ще один тест", function() ());


    У попередньому прикладі всі твердження викликалися синхронно, тобто виконувались одне одним. У реальному світі існує безліч асинхронних функцій, таких як запити AJAX чи функції setTimeout()і setInterval(). Як нам тестувати такий тип функцій? QUnit має спеціальний тип тестів, який називається "асинхронний тест" та призначений для асинхронного тестування:

    Спочатку спробуємо написати тест звичайним способом:

    Test("Асинхронний тест", function() ( setTimeout(function() ( ok(true); ), 100) ))


    Виглядає так, ніби у тесті немає жодних тверджень. Тому що твердження виконалося синхронно, але на момент виклику функції тест вже закінчився.

    Правильний варіант тестування нашого прикладу:

    Test("Асинхронний тест", function() ( // Перекладаємо тест у режим "пауза" stop(); setTimeout(function() ( ok(true); // Після виклику затвердження // продовжуємо тест start(); ), 100) ))


    Ми використовували функцію stop()для зупинки тесту, а після виконання затвердження знову запускали тест за допомогою функції start().

    Виклик функції stop()відразу після виклику функції test()є дуже поширеною практикою. Тому QUnit має спеціальне скорочення: asyncTest(). Попередній приклад можна переписати у вигляді:

    AsyncTest("Асинхронний тест", function() ( // Тест автоматично переводиться в режим "пауза" setTimeout(function() ( ok(true); // Після виклику затвердження // продовжуємо тест start(); ), 100) ) )

    Є один момент, над яким варто замислитись: функція setTimeout()завжди викликає свою функцію, а якщо тестувати іншу функцію (наприклад, виклик AJAX). Як бути впевненим, що зворотну функцію буде викликано? Якщо зворотна функція не буде викликана, функція start()теж залишиться без виклику і весь тест "підвисне":


    Можна організувати тест так:

    // функція користувача function ajax(successCallback) ( $.ajax(( url: "server.php", success: successCallback )); ) test("Асинхронний тест", function() ( // Зупиняємо тест і // будемо повідомляти про помилку, якщо функція start() не буде викликана через 1 секунду stop(1000); ajax(function()

    У функцію stop()передається значення таймауту. Тепер QUnit отримав вказівку: “якщо функція start()не буде викликана після закінчення таймууту, слід вважати цей тест проваленим”. Тепер весь тест не "підвисне" і буде видано попередження, якщо щось піде не так, як потрібне.

    Тепер розглянемо випадок багатьох асинхронних функцій. Де розміщувати функцію start()? Потрібно розміщувати її у функції setTimeout():

    // функція користувача function ajax(successCallback) ( $.ajax(( url: "server.php", success: successCallback )); ) test("Асинхронний тест", function() ( // Зупиняємо тест stop(); ajax (function() ( // ...асинхронне затвердження)) ajax(function() ( // ...асинхронне затвердження)) setTimeout(function() ( start(); ), 2000);

    Перед продовженням тесту значення таймауту має бути достатнім для виконання викликів обох функцій. Якщо одна з функцій не буде викликана, як визначити, яка саме? Для цього є функція expect():

    // Користувальницька функція function ajax(successCallback) ( $.ajax(( url: "server.php", success: successCallback )); ) test("Асинхронний тест", function() ( // Зупиняємо тест stop(); / / Повідомляємо QUnit, що ми очікуємо виконання трьох тверджень expect(3); ) ( start(); ), 2000); ))

    Ми передаємо у функцію expect()кількість тверджень, які планується виконати. Якщо одне із тверджень не буде виконане, ви отримаєте повідомлення про те, що йдеться не так, як планується.

    Є короткий запис для використання expect(): потрібно передати кількість затверджень, що плануються, як другий параметр test()або asyncTest():

    // функція користувача function ajax(successCallback) ( $.ajax(( url: "server.php", success: successCallback )); ) // Повідомляємо QUnit, що ми очікуємо виконання 3 тверджень test("asynchronous test", 3, function() ( // Зупиняємо тест stop(); ajax(function() ( ok(true); )) ajax(function() ( ok(true); ok(true); )) setTimeout(function() ( start (); ), 2000); ))

    Висновок

    У цьому уроці ми навели все, що потрібно для початку роботи з QUnit. Модульне тестування – чудовий метод для перевірки коду перед його використанням. Якщо ви ніколи раніше не використовували жодних тестів, саме час розпочати.

    На прикладі простого калькулятора на Node.js. Тестуватимемо за допомогою фреймворку Mocha.

    Що має вміти наша програма:

    • Складати, віднімати, ділити та множити будь-які два числа;
    • Показувати попередження та завершувати роботу, якщо було введено щось відмінне від числа;
    • Також має бути інтерфейс командного рядка, щоб кінцевий споживачміг скористатися програмою.

    Що нам потрібно:

    • Node.js та npm;
    • Знання JavaScript: синтаксис і структура коду, типи даних, математичні операції та умовні вирази.

    З цілями розібралися, можна приступати до настроювання середовища для тестування та розробки.

    Налаштовуємо середу

    Оскільки ми використовуємо Node.js, потрібно створити локальне оточення для файлів та залежностей.

    Створіть нову папку calc. У командному рядку перейдіть до цієї директорії і створіть новий проект командою npm init, яка створить новий файл package.jsonдля нашої програми.

    Вам запропонують ввести ім'я пакета, версію, опис та іншу інформацію про пакет. Ви можете ввести ім'я calc.jsі далі тиснути Enterдля надання значень за замовчуванням. Коли ви дійдете до test command, введіть mocha - це фреймворк для тестування, який ми будемо використовувати:

    test command: mocha

    Після введення всієї інформації скрипт створить файл package.json, який виглядає приблизно так:

    ( "name": "calc.js", "version": "1.0.0", "description": "Простий калькулятор на Node.js", "main": "index.js", "scripts": ( " test": "mocha" ), "author": "", "license": "ISC" )

    Останній крок на даному етапі – встановлення Mocha. Введіть наступну команду для встановлення:

    Npm install --save-dev mocha

    Після застосування цієї команди з'явиться папка node_modules, файл package-lock.json, а у файлі package.jsonз'являться наступні рядки:

    "devDependencies": ( "mocha": "^4.0.1" )

    Створіть файл test.js. Ми скористаємося вбудованим у Node.js модулем assert, щоб перевірити вірність рівності true та true . Так як воно правильне, тест має пройти успішно:

    Const assert = require ("assert"); it("має повертати true", () => ( assert.equal(true, true); ));

    Тепер запустіть тест із командного рядка:

    $ npm test > mocha ✓ має повертати true 1 passing (8ms)

    Тест пройшов як і очікувалося, тому з налаштуванням середовища покінчено. Видаліть із test.jsвсе, крім рядка const assert = require ("assert"); .

    Ми будемо використовувати файл test.jsпротягом усього процесу створення програми. Створіть ще два файли: operations.jsдля арифметичних та валідаційних функцій та calc.jsдля самої програми. Ми використовуємо так багато файлів, щоб вони не ставали надто довгими та складними. Ось наш поточний список файлів:

    • calc.js;
    • node_modules;
    • operations.js;
    • package-lock.json;
    • package.json;
    • test.js;

    Давайте додамо перший справжній тест для нашої програми.

    Додаємо математичні операції

    Перш за все, наша програма повинна вміти складати, віднімати, ділити і множити будь-які два числа. Отже, кожної з цих операцій ми маємо створити окрему функцію.

    Почнемо зі складання. Ми напишемо тест, у якому однозначно вийде очікувана сума двох чисел. У коді нижче ми перевіряємо, чи дорівнює сума 1 і 3 за допомогою функції add() 4:

    Const assert = require ("assert"); it("правильно знаходить суму 1 і 3", () => ( assert.equal(add(1, 3), 4); ));

    Після запуску тесту за допомогою команди npm test ми бачимо таке:

    > mocha 0 passing (9ms) 1 failing 1) правильно знаходить суму 1 і 3: ReferenceError: add is not defined at Context.it (test.js:5:16) npm ERR! Test failed. Подивіться на more details.

    Тест провалився з повідомленням ReferenceError: add is not defined . Ми тестуємо функцію add() якої ще немає, тому такий результат цілком очікуємо.

    Створимо функцію add() у файлі operations.js:

    Const add = (x, y) => (+x) + (+y);

    Ця функція приймає два аргументи x та y і повертає їхню суму. Ви могли помітити, що ми пишемо (+x) + (+y) , а не x + y . Ми використовуємо унарний оператор для приведення аргументу до числа, на випадок, якщо введення буде рядком.

    Примітка Тут використовується додана ES6 стрілкова функція і неявне повернення.

    Оскільки ми використовуємо Node.js і розбиваємо код на безліч файлів, потрібно скористатися module.exports для експорту коду:

    Const add = (x, y) => (+x) + (+y); module.exports = (add)

    На початку файлу test.jsми імпортуємо код з operations.jsза допомогою require(). Оскільки ми використовуємо функцію через змінну operations , потрібно поміняти add() на operations.add() :

    Const operations = require("./operations.js"); const assert = require ("assert"); it("правильно знаходить суму 1 і 3", () => ( assert.equal(operations.add(1, 3), 4); ));

    Запускаємо тест:

    $ npm test > mocha ✓ правильно знаходить суму 1 та 3 1 passing (8ms)

    Тепер у нас є функція, що працює, і тести проходять успішно. Оскільки функції інших операцій працюють подібним чином, додати тести для subtract() , multiply() і divide() не складе труднощів:

    It("правильно знаходить суму 1 і 3", () => ( assert.equal(operations.add(1, 3), 4); )); it("правильно знаходить суму -1 і -1", () => ( assert.equal(operations.add(-1, -1), -2); )); it("правильно знаходить різницю 33 і 3", () => ( assert.equal(operations.subtract(33, 3), 30); )); it("правильно знаходить твір 12 і 12", () => ( assert.equal(operations.multiply(12, 12), 144); )); it("правильно знаходить приватне 10 і 2", () => ( assert.equal(operations.divide(10, 2), 5); ));

    Тепер створимо та експортуємо всі функції в test.js:

    Const add = (x, y) => (+x) + (+y); const subtract = (x, y) => (+x) - (+y); const multiply = (x, y) => (+x) * (+y); const divide = (x, y) => (+x) / (+y); module.exports = ( add, subtract, multiply, divide, )

    І запустимо нові тести:

    $ npm test > mocha ✓ правильно знаходить суму 1 та 3 ✓ правильно знаходить суму -1 та -1 ✓ правильно знаходить різницю 33 та 3 ✓ правильно знаходить твір 12 та 12 ✓ правильно знаходить приватне 10 та 2 5 passing (8ms)

    Всі тести проходять успішно, тому тепер ми можемо бути впевнені, що основні функції нашої програми працюватимуть коректно. Тепер можна зайнятися додатковою валідацією.

    Додаємо валідацію

    На даний момент, коли користувач вводить число та вибирає потрібну операцію, все працює нормально. Однак що трапиться, якщо спробувати знайти суму числа та рядка? Програма спробує виконати операцію, але через те, що вона чекає числа, вона поверне NaN .

    Замість повертати якісь незрозумілі значення, настав час виконати друге завдання - зробити так, щоб додаток показував попередження і завершував свою роботу, якщо введений аргумент не є числом.

    Спочатку потрібно написати функцію, яка перевірятиме, чи є введення числом чи ні. Додаток має працювати тільки з числами, тому ми оброблятимемо три ситуації:

    1. Обидва введення - числа.
    2. Одне введення – число, а інше – рядок.
    3. Обидва введення - рядки.
    it("повідомляє про помилку при використанні рядка замість числа", () => ( assert.equal(operations.validateNumbers("sammy", 5), false); )); it("повідомляє про помилку при використанні двох рядків замість чисел", () => ( assert.equal(operations.validateNumbers("sammy", "sammy"), false); )); it("успіх при використанні двох чисел", () => ( assert.equal(operations.validateNumbers(5, 5), true); ));

    Функція validateNumbers() перевірятиме обидва параметри. Функція isNaN() перевіряє, чи параметр не є числом, і якщо ні, то повертає false . В іншому випадку вона повертає true, що означає успішну валідацію.

    Const validateNumbers = (x, y) => ( if (isNaN(x) && isNaN(y)) ( return false; ) return true; )

    Не забудьте додати validateNumbers до module.exports в кінці файлу. Тепер можна запускати нові тести:

    $ npm test 1) повідомляє про помилку при використанні рядка замість числа ✓ повідомляє про помилку при використанні двох рядків замість чисел ✓ успіх при використанні двох чисел 7 passing (12ms) 1 failing 1) повідомляє про помилку при використанні рядка замість числа: AssertionError : true == false + expected - actual -true +false

    Два тести пройшли, але один провалився. Перевірка на введення двох чисел пройшла успішно, як і перевірка на введення двох рядків. Чого не можна сказати про перевірку на введення рядка та числа.

    Якщо поглянути на нашу функцію ще раз, можна помітити, що обидвапараметра мають бути NaN, щоб функція повернула false. Якщо ми хочемо досягти того ж ефекту, коли хоча б один із параметрів дорівнює NaN, потрібно замінити && на || :

    Const validateNumbers = (x, y) => ( if (isNaN(x) || isNaN(y)) ( return false; ) return true; )

    Якщо після цих змін знову запустити npm test, то всі тести пройдуть успішно:

    ✓ повідомляє про помилку при використанні рядка замість числа ✓ повідомляє про помилку при використанні двох рядків замість чисел ✓ успіх при використанні двох чисел 8 passing (9ms)

    Ми протестували всю функціональність нашої програми. Функції успішно виконують математичні операції та перевіряють введення. Фінальний етап - створення інтерфейсу користувача.

    Створюємо інтерфейс

    Потрібні функції ми вже маємо, але користувач поки що ніяк не може ними скористатися. Тому нам потрібний інтерфейс. Для нашої програми ми створимо інтерфейс командного рядка.

    На даний момент файл calc.jsмає бути порожнім. Тут і зберігатиметься наша програма. Спочатку потрібно імпортувати функції з operations.js:

    Const operations = require("./operations.js");

    Сам інтерфейс використовуватиме вбудований в Node.js CLI-модуль Readline:

    Const readline = require ("readline");

    Після імпортування всього, що потрібно, можна приступити до створення програми. Для створення інтерфейсу ми будемо використовувати readline, доступний через змінну rl:

    Const rl = readline.createInterface(( input: process.stdin, output: process.stdout ));

    Перше, що користувач повинен бачити після запуску програми, - вітальне повідомлення та інструкції щодо використання. Для цього ми скористаємося console.log() :

    Console.log(` Calc.js Ви відкрили калькулятор на Node.js! Версія: 1.0.0. Використання: користувач повинен ввести два числа, а потім вибрати, що з ними зробити. `);

    Перш ніж ми займемося самими функціями калькулятора, перевіримо, що console.log() працює як треба. Ми зробимо так, щоб програма виводила повідомлення та завершувала роботу. Для цього додайте наприкінці виклик методу rl.close() .

    Щоб запустити програму, введіть node та ім'я файлу:

    $ node calc.js Calc.js Ви відкрили калькулятор на Node.js! Версія: 1.0.0. Використання: користувач повинен ввести два числа, а потім вибрати, що з ними зробити.

    Програма виводить вітальне повідомлення та завершує свою роботу. Тепер потрібно додати введення користувача. Від користувача потрібно наступне: вибрати два числа та одну операцію. Кожне введення буде запитуватись методом rl.question() :

    Rl.question("Введіть перше число: ", (x) => ( rl.question("Введіть друге число: ", (y) => ( rl.question(` Виберіть одну з наступних операцій) Додавання (+) Віднімання) (-) Множення (*) Поділ (/) Ваш вибір: `, (choice) => ( // тут ще з'явиться код rl.close(); )); )); ));

    Змінної x надається перше число, y - друге, а choice - обрана операція. Тепер наша програма запитує введення, але нічого не робить із отриманими даними.

    Після третього введення потрібно перевірити, чи були введені тільки числа. Для цього скористаємося функцією validateNumbers(). За допомогою оператора НЕ ми перевіримо, чи були введені числа, і якщо це не так, завершимо роботу програми:

    If (!operations.validateNumbers(x, y)) ( console.log("Можна вводити тільки числа! Будь ласка, перезапустіть програму."); )

    Якщо все введено правильно, то тепер необхідно запустити відповідний операції спосіб, створений раніше. Для обробки чотирьох можливих варіантів вибору ми скористаємося виразом switch і виведемо результат операції. Якщо вибрано неіснуючу операцію, буде виконано блок default , що повідомляє користувачеві про необхідність повторити спробу:

    If (!operations.validateNumbers(x, y)) ( console.log("Можна вводити тільки числа! Будь ласка, перезапустіть програму."); ) else ( switch (choice) ( case "1": console.log(`Сума $(x) і $(y) дорівнює $(operations.add(x, y)).`), break, case "2": console.log(`Різниця $(x) і $(y) дорівнює $( operations.subtract(x, y)).`); break; case "4": console.log(`Приватне $(x) і $(y) дорівнює $(operations.divide(x, y)).`); break; перезапустіть програму та виберіть число від 1 до 4."); break; ) )

    Примітка У функціях console.log() використовуються шаблонні рядки , що допускають використання виразів.

    /** * Простий калькулятор на Node.js, який використовує calculator app that uses * вбудований інтерфейс командного рядка Readline. */ const operations = require("./operations.js"); const readline = require ("readline"); // Використовуємо readline для створення інтерфейсу const rl = readline.createInterface((input: process.stdin, output: process.stdout)); console.log(` Calc.js Ви відкрили калькулятор на Node.js! Версія: 1.0.0. Використання: користувач повинен ввести два числа, а потім вибрати, що з ними зробити. `); rl.question("Введіть перше число: ", (x) => ( rl.question("Введіть друге число: ", (y) => ( rl.question(` Виберіть одну з наступних операцій) Додавання (+) Віднімання) (-) Розмноження (*) Поділ (/) Ваш вибір: `, (choice) => ( if (!operations.validateNumbers(x, y)) ( console.log("Можна вводити тільки числа! Будь ласка, перезапустіть програму). "); ) else ( switch (choice) ( case "1": console.log(`Сума $(x) і $(y) дорівнює $(operations.add(x, y)).`); break; case "2": console.log(`Різниця $(x) і $(y) дорівнює $(operations.subtract(x, y)).`); x) і $(y) одно $(operations.multiply(x, y)).`), break; divide(x, y)).`); break; ;));

    Тепер наша програма готова. Перевіримо його роботу наостанок. Введемо 999 і 1 і виберемо операцію віднімання:

    $ node calc.js Введіть перше число: 999 Введіть друге число: 1 Ваш вибір: 2 Різниця 999 і 1 дорівнює 998.

    Програма успішно завершила свою роботу, вивівши правильний результат. Вітаємо, ви написали простий калькулятор за допомогою Node.js та вивчили основи TDD-розробки.

    © 2022 androidas.ru - Все про Android