Найкращі практики тестування Node.js та JavaScript (2019)

Важлива примітка: Ця стаття стала сховищем GitHub з додатковими 15 найкращими практиками та дискусіями в громаді

Короткий вступ

Як незалежний консультант Node.js, я щороку займаюся та переглядаю 10+ проектів, і мої клієнти з повагою просять зосередитись на тестуванні. Кілька місяців тому я почав документувати тут уявлення та повторювані помилки, які я спостерігаю на місцях, і раптом він накопичився на 30 найкращих методів тестування.

Наведені нижче ідеї охоплюють такі теми, як вибір правильних типів тестування, правильне їх кодування, вимірювання їх ефективності та правильне розміщення їх у конвеєрі CI / CD. Деякі приклади проілюстровані за допомогою Jest, інші - з Mocha - ця публікація менше стосується інструментарію та більше - правильного підходу та методик.

Мене звуть Йоні Голдберг, незалежний консультант Node.JS та співавтор кращих практик Node.js. Я працюю з клієнтами в США, Європі та Ізраїлі над поліруванням їх програм Node.js. Серед моїх послуг - також планування тестів, огляд тесту та налаштування CI / CD. Слідкуйте за мною у Twitter ️

Оглянув та покращив Бруно Шеуфлер

️ 0. Золоте правило: Тестування повинно залишатися мертвим - просто і ясно, як день

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

Тестування не слід трактувати як традиційний код програми - типова команда кидає виклик з підтримкою свого основного додатка (будь-які функції, які ми кодуємо і продаємо), вона не може терпіти додаткових складних «проектів». Якщо тестування зростатиме додатковим джерелом болю - воно відмовиться або значно сповільнить розвиток.

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

*** Розділ : Тестова анатомія ***

Includ ️ 1. Включіть 3 частини в кожну назву тесту

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

(1) Що тестується? Наприклад, метод ProductsService.addNewProduct

(2) За яких обставин та сценарію? Наприклад, до методу не передається ціна

(3) Який очікуваний результат? Наприклад, новий товар не затверджено

В іншому випадку: розгортання просто не вдалося, тест під назвою "Додати продукт" не вдався. Це говорить вам про те, що саме не працює?

Right Правильний приклад: Тестова назва, що складається з 3 частин

Example Робити це правильно Приклад: Звіт про випробування нагадує документ із вимогами

До кожного тесту включайте 3 частини, розмовляйте мовою продукту

2. Опишіть очікування мовою продукту: використовуйте твердження у стилі BDD

Робити: Кодування ваших тестів у декларативному стилі дозволяє читачеві одразу отримати помилку, не витрачаючи навіть жодного циклу мозок-процесор. Коли ви пишете імперативний код, наповнений умовною логікою, читача відкидають напружений розумовий настрій. У цьому сенсі кодуйте очікування в людській мові, декларативному стилі BDD, використовуючи очікування чи слід та не використовуючи спеціальний код. Якщо Chai & Jest не містять потрібного твердження, і це дуже повторюється, подумайте про те, щоб продовжити Jest matcher (Jest) або написати користувальницький плагін Chai

В іншому випадку: команда напише менше тесту та прикрасить дратівливих з допомогою .skip ()

Example Приклад антитіла: Читач повинен проглядати не такий короткий та обов'язковий код, щоб отримати тестову історію

Як правильно робити приклад: знежирення через наступний декларативний тест - вітер

️ 3. Підводка з плагінами, призначеними для тестування

Виконайте: Набір плагінів ESLint був створений спеціально для перевірки моделей тестових кодів та виявлення проблем. Наприклад, eslint-plugin-mocha попередить, коли тест буде написаний на глобальному рівні (не є сином оператора description ()) або коли тести будуть пропущені, що може призвести до помилкової думки, що всі тести проходять. Аналогічно, eslint-plugin-vice може, наприклад, попереджати, коли тест взагалі не має тверджень (нічого не перевіряючи)

В іншому випадку: якщо 90% покриття коду та 100% зелені тести змусять ваше обличчя отримати велику посмішку лише до тих пір, поки ви не зрозумієте, що багато тестів не претендують ні на що і багато тестових наборів було просто пропущено. Сподіваємось, ви нічого не розгорнули на основі цього помилкового спостереження

Example Приклад анти-візерунка: тестовий випадок, повний помилок, на щастя, всі виявляють Лінтери

️ 4. Дотримуйтесь тестування у чорному ящику: протестуйте лише загальнодоступні методи

Робити: Тестування внутрішніх справ майже не потребує великих витрат. Якщо ваш код / ​​API дають правильні результати, чи варто реально інвестувати свої наступні 3 години в тестування того, як воно працювало внутрішньо, а потім підтримувати ці тендітні тести? Щоразу, коли перевіряється поведінка громадськості, приватна реалізація також непрямо перевіряється, і ваші тести будуть порушені, лише якщо є певна проблема (наприклад, неправильний вихід). Цей підхід також називають поведінковим тестуванням. З іншого боку, якщо ви протестуєте внутрішні (підхід білого поля) - ваш фокус зміщується від планування результату компонента до деталей, що містять солоність, і ваш тест може зламатися через незначні рефактори коду, хоча результати прекрасні - це різко збільшує обслуговування тягар

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

Example Приклад антитіла: Тестовий випадок - це тестування внутрішніх даних без поважних причин

️️5. Виберіть правильний парний тест: уникайте глузувань на користь заглушок та шпигунів

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

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

Наприклад, якщо ви хочете перевірити, як ваша програма поводиться розумно, коли платіжна служба вимкнеться, ви можете заглушити платіжну послугу і запустити деякий повернення "Без відповіді", щоб гарантувати, що тестовий пристрій поверне правильне значення. Це перевіряє нашу поведінку / відповідь / результат програми за певних сценаріїв. Ви також можете використовувати шпигуна, щоб стверджувати, що повідомлення електронної пошти було надіслано, коли ця послуга не працює - це знову перевірка поведінки, яка, ймовірно, з’явиться в документі вимог ("Надіслати електронний лист, якщо платіж не вдалося зберегти"). З іншого боку, якщо ви знущаєтеся з Платіжної служби та переконуєтесь, що вона викликалася правильними типами JavaScript - ваш тест зосереджений на внутрішніх речах, які нічого не мають з функціоналом програми та, ймовірно, часто змінюються

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

Example Приклад анти-візерунку: знущається зосереджуватися на внутрішніх місцях

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

️ 6. Не "foo", використовуйте реалістичні вхідні дані

Робити: Часто виробничі помилки виявляються під дуже специфічним та дивовижним вкладом - чим реалістичніший тестовий вклад, тим більше шансів рано зараховувати помилок. Використовуйте виділені бібліотеки типу Faker для генерування псевдореальних даних, що нагадують різноманітність та форму виробничих даних. Наприклад, такі бібліотеки будуть генерувати випадкові, але реалістичні телефонні номери, імена користувачів, кредитні картки, назви компаній і навіть текст "lorem ipsum". Подумайте навіть про імпорт реальних даних із виробничого середовища та використання у своїх тестах. Хочете перейти на наступний рівень? див. наступну кулю (тестування на основі властивостей)

Інакше: усі ваші тести розробки виявляться помилково зеленими, коли ви використовуєте синтетичні матеріали типу "Foo", але тоді виробництво може почервоніти, коли хакер перейде в неприємний рядок, як "@ 3e2ddsf. ## '1 fdsfds. fds432 AAAA ”

Example Антидіапазонний приклад: тестовий набір, який проходить через нереалістичні дані

RightЗастосування правильного прикладу: рандомізація реалістичного введення

7. Тестуйте безліч комбінацій вводу за допомогою тестування на основі властивостей

Робити: Зазвичай ми вибираємо кілька вхідних зразків для кожного тесту. Навіть коли формат введення нагадує дані в реальному світі (див. Куля "Не foo"), ми охоплюємо лише декілька вхідних комбінацій (метод ('', true, 1), метод ("string", false ", 0) ), Однак у виробництві API, який викликається з 5 параметрами, може викликати тисячі різних перестановок, одна з них може зменшити наш процес (див. Тест Fuzz). Що робити, якщо ви могли написати єдиний тест, який автоматично надсилає 1000 перестановок різних входів та збирає, для введення якого наш код не поверне правильну відповідь? Тестування на основі властивостей - це техніка, яка робить саме це: надсилаючи всі можливі комбінації входів на тестовий пристрій, це збільшує безвідмовність пошуку помилки. Наприклад, заданий метод - addNewProduct (id, ім'я, isDiscount) - підтримуючі бібліотеки називатимуть цей метод з багатьма комбінаціями (число, рядок, булева), наприклад (1, "iPhone", false), (2, "Galaxy ”, Правда). Ви можете запустити тестування на основі властивостей за допомогою свого улюбленого тестового бігуна (Mocha, Jest тощо), використовуючи бібліотеки, такі як js-verify або тестова перевірка (набагато краща документація). Оновлення: Ніколас Дюбієн пропонує в коментарях нижче перевірити швидку перевірку, яка, здається, пропонує деякі додаткові функції, а також активно підтримуватися

Інакше: підсвідомо ви вибираєте тестові входи, які охоплюють лише кодові шляхи, які добре працюють. На жаль, це знижує ефективність тестування як транспортного засобу на виявлення помилок

Правильно робити приклад: Тестування багатьох вхідних перестановок за допомогою "mocha-testcheck"

️ 8. Залишайтеся в рамках тесту: Мінімізуйте зовнішніх помічників та абстракцій

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

Хороший виробничий код є факторним; хороший тестовий код очевидний ... Коли ви пишете тест, подумайте про наступного розробника, який побачить перерву тесту. Вони не хочуть читати весь тестовий набір, і вони, звичайно, не хочуть читати ціле дерево спадкування тестових утиліт.

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

Інакше: раптом опинилися 4 помічники в тестовому наборі, 2 з них успадковано від базової утиліти, багато налаштувань та розривів гачків? поздоровлення, щойно ви виграли ще один складний проект для підтримки, ви можете незабаром написати тести проти свого тестового набору

Example Антидіапазонний приклад: химерна та непряма структура тесту. Ви розумієте тестовий випадок, не переходячи до зовнішніх залежностей?

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

9. Уникайте глобальних тестових приладів та насіння, додайте дані за тест

Виконайте: Виконуючи за золотим правилом (куля 0), кожен тест повинен додавати і діяти на власному наборі рядків БД, щоб запобігти з’єднанню та легко міркувати про тестовий потік. Насправді це часто порушується тестерами, які закладають БД з даними перед запуском тестів (також відомим як «тестовий пристрій») задля підвищення продуктивності. Хоча продуктивність справді є важливою проблемою - її можна пом'якшити (див. Пул "Тестування компонентів"), проте складність тесту - це дуже болісна печаль, яка повинна керувати іншими міркуваннями більшість часу. Практично зробіть кожен тестовий випадок, явно додайте потрібні йому записи DB та дійте лише на ці записи. Якщо продуктивність стає критичною проблемою - може бути досягнутий збалансований компроміс у вигляді висіву єдиного набору тестів, які не мутують дані (наприклад, запити)

В іншому випадку: небагато тестів не вдалося, розгортання припинено, наша команда зараз витратить дорогоцінний час, чи є у нас помилка? давайте дослідимо, о ні - здається, два тести мутували однакові дані насіння

Example Приклад антитіла: тести не є незалежними та покладаються на деякий глобальний гачок, щоб подавати глобальні дані БД

ExampleЗастосування правильного прикладу: ми можемо залишатися в рамках тесту, кожен тест діє на власному наборі даних

️ 10. Не вловлюйте помилок, очікуйте їх

Зробіть так: Коли ви намагаєтесь стверджувати, що деякий вхід викликає помилку, може бути правильним використовувати пробний підсумок і стверджувати, що було введено пункт про вилов. Результат - незручний і багатослівний тестовий випадок (приклад нижче), який приховує простий намір тесту та очікувані результати

Більш елегантною альтернативою є використання однорядкового виділеного твердження Chai: очікувати (метод) .to.throw (або в Jest: очікувати (метод) .toThrow ()). Абсолютно обов’язково також переконатися, що виняток містить властивість, яка вказує на тип помилки, інакше, отримавши лише загальну помилку, програма не зможе зробити багато, а не показати невтішне повідомлення користувачеві

В іншому випадку: складно зробити висновки з тестових звітів (наприклад, звітів про ІС), що пішло не так

Example Приклад антидіаграми: довгий тестовий випадок, який намагається стверджувати про помилку із спробою лову

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

️10. Позначте свої тести

Діймо: різні тести повинні працювати в різних сценаріях: швидкий дим, без IO, тести повинні запускатися, коли розробник зберігає або робить файл, повні тести, що завершуються, закінчуються зазвичай під час подання нового запиту на витягнення тощо. Це можна досягти, позначивши тести за такими ключовими словами, як #cold #api #sanity, щоб ви могли поздоровитись з тестовим джгутом і викликати потрібний підмножина. Наприклад, саме так ви могли б викликати лише групу тестування на здоровість із Mocha: mocha - grep 'sanity'

В іншому випадку: запуск усіх тестів, включаючи тести, які виконують десятки запитів БД, у будь-який час, коли розробник робить невеликі зміни, може бути дуже повільним і не дає розробникам подалі від запуску тестів

Робити це правильно Приклад: теги для тегів як "# холодний тест" дозволяють тестувальнику виконувати лише швидкі тести (Cold === швидкі тести, які не мають IO і можуть виконуватися часто, навіть коли розробник набирає)

11. Інші загальнодоступні гігієни тестування

Виконайте: Ця публікація зосереджена на порадах щодо тестування, які стосуються або принаймні можуть бути пояснені з допомогою Node JS. Однак ця куля об'єднує декілька підказок, що не стосуються Вузла, які добре відомі

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

Інакше: вам не вистачить перлів мудрості, які збирали десятиліттями

*** Розділ : Типи випробувань ***

️ 12. Збагатіть свій тестовий портфель: Подивіться понад тести одиниць та піраміди

Робіть: піраміда для тестування, хоча й 10 років, - це чудова та відповідна модель, яка пропонує три типи тестування та впливає на тестувальну стратегію більшості розробників. У той же час з’явилося більше, ніж жменька нових блискучих методик тестування і ховаються в тіні піраміди тестування. З огляду на всі кардинальні зміни, які ми спостерігали за останні 10 років (мікросервіси, хмара, без серверів), чи можливо, одна досить стара модель відповідатиме * всім * типам додатків? чи не повинен світ тестування розглянути можливість прийому нових методів тестування?

Не помиляйтеся, у 2019 році тестова піраміда, тести TDD та модулі залишаються потужною технікою і, мабуть, найкраща відповідність для багатьох застосувань. Тільки як і будь-яка інша модель, незважаючи на її корисність, іноді повинна помилятися. Наприклад, розглянемо додаток IOT, який передає багато подій у шину повідомлень на зразок Kafka / RabbitMQ, яка потім переходить у деякий сховище даних і в кінцевому підсумку запитується деяким аналітичним інтерфейсом. Чи варто нам реально витрачати 50% нашого тестувального бюджету на написання одиничних тестів для програми, орієнтованої на інтеграцію та майже не має логіки? У міру збільшення різноманітності типів додатків (ботів, криптовалют, Alexa-навичок) більше шансів знайти сценарії, де тестова піраміда не найкраще відповідає.

Настав час збагатити свій тестовий портфель та ознайомитись з більш типами тестування (наступні кулі пропонують декілька ідей), розумні моделі, такі як тестова піраміда, але також відповідають тестуючим типам реальним проблемам, з якими ви стикаєтеся ("Привіт, наш API порушено, давайте запишемо тестування контрактів, орієнтованих на споживачів! '), диверсифікуйте свої тести, як інвестор, який будує портфель на основі аналізу ризиків - оцініть, де можуть виникнути проблеми, і порівняйте деякі заходи профілактики для зменшення цих потенційних ризиків

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

В іншому випадку: ви пропустите деякі інструменти з дивовижною рентабельністю інвестицій, такі як Fuzz, ворсинка і мутація можуть забезпечити цінність за 10 хвилин

Як правильно робити приклад: Сінді Шрідхаран пропонує багате тестове портфоліо у своєму дивовижному пості "Тестування мікросервісів - здоровий шлях"

Приклад: YouTube: “Поза тестування одиниць: 5 блискучих вузлів. Види тестів JS (2018)” (Йоні Голдберг)

5 блискучих методик тестування Йоні Голдберг

️ 13. Тестування компонентів може бути найкращим справою

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

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

В іншому випадку: Ви можете витратити довгі дні на написання тестових одиниць, щоб дізнатися, що у вас є лише 20% охоплення системи

Як правильно це зробити: Приклад Supertest дозволяє наближатись до Express API в процесі (швидко та охоплювати багато шарів)

️ 14. Переконайтесь, що нові версії не порушують API, використовуючи контракти, орієнтовані на споживачів

Робіть так: у вашій Microservice є кілька клієнтів, і ви запускаєте кілька версій сервісу з міркувань сумісності (підтримуючи всіх щасливими). Потім ви змінюєте поле і "бум!", Якийсь важливий клієнт, який покладається на це поле, розлючений. Це Catch-22 у світі інтеграції: для сервера дуже складно врахувати всі багаторазові очікування клієнтів. З іншого боку, клієнти не можуть проводити тестування, оскільки сервер контролює дати випуску. Споживчі договори та рамки PACT були народжені для формалізації цього процесу з дуже руйнівним підходом - не сервер визначає сам план тестування, а клієнт визначає тести ... сервера! PACT може записувати очікування клієнта і розміщувати в загальному місці "брокера", тому сервер може витягнути очікування та запустити кожну збірку за допомогою бібліотеки PACT для виявлення порушених контрактів - очікування клієнта, яке не виконується. Таким чином, всі невідповідності API сервер-клієнт виявляються на початку впродовж збирання / CI і можуть врятувати вас від великого розладу

В іншому випадку: альтернативи виснажують ручне тестування або страх розгортання

Example Як правильно це зробити:

️ 15. Перевірте середній рівень відокремлено

Робити: Багато хто уникає тестування середнього програмного забезпечення, оскільки вони представляють невелику частину системи та потребують живого сервера Express. Обидві причини помиляються - Middlewares невеликі, але впливають на всі або більшість запитів і можуть бути легко перевірені як чисті функції, які отримують {req, res} JS-об'єкти. Щоб перевірити функцію проміжного програмного забезпечення, слід просто викликати її та шпигувати (наприклад, використовуючи Sinon) щодо взаємодії з об'єктами {req, res}, щоб переконатися, що функція виконала правильну дію. Бібліотечний вузол-mock-http додає його ще більше і враховує об'єкти {req, res}, а також шпигує за їх поведінкою. Наприклад, він може стверджувати, чи відповідає статус http, встановлений на res об'єкті, очікуванню (див. Приклад нижче)

В іншому випадку: помилка в програмі Express Middle = == помилка у всіх або більшості запитів

Right Робити це правильно Приклад: Тестування проміжного програмного забезпечення ізольовано, не видаючи мережеві дзвінки та пробуджуючи всю машину Express

️ 16. Вимірювання та рефактор за допомогою інструментів статичного аналізу

Робити: Використання інструментів статичного аналізу допомагає, надаючи об'єктивні способи покращити якість коду та зберегти код. Ви можете додати інструменти статичного аналізу до вашої збірки CI, щоб перервати, коли він знайде запахи коду. Його основні продажні точки перед простою лінією - це можливість перевірити якість у контексті декількох файлів (наприклад, виявити дублювання), виконати розширений аналіз (наприклад, складність коду) та слідкувати за історією та ходом проблем з кодом. Два приклади інструментів, якими ви можете скористатися - Sonarqube (2600+ зірок) і Code Climate (1500+ зірок)

Кредит: Кіт Холлідей

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

Робити це правильно Приклад: CodeClimat, комерційний інструмент, який може визначити складні методи:

️ 17. Перевірте свою готовність до хаосу, пов’язаного з Вузлом

Робити: Як не дивно, більшість тестувань програмного забезпечення стосуються лише логіки та даних, але деякі найгірші речі, які трапляються (і насправді їх важко пом'якшити), є інфраструктурними проблемами. Наприклад, чи ви коли-небудь перевіряли, що відбувається, коли ваша процесова пам'ять перевантажена, або коли сервер / процес гине, чи ваша система моніторингу усвідомлює, коли API стає на 50% повільніше ?. Щоб перевірити та пом'якшити цей тип поганих речей - хаос-інженерія народилася Netflix. Він спрямований на те, щоб забезпечити обізнаність, рамки та інструменти для тестування нашої програми на стійкість до хаотичних проблем. Наприклад, один із відомих інструментів, мавпа хаосу, випадково вбиває сервери, щоб гарантувати, що наш сервіс все ще може обслуговувати користувачів і не покладатися на один сервер (є також версія Kubernetes, кубе-мавпа, яка вбиває стручки). Усі ці інструменти працюють на рівні хостингу / платформи, але що робити, якщо ви хочете протестувати та генерувати чистий хаос Node, як-от перевірити, як ваш Node-процес справляється з невловимими помилками, нерозробленим обіцянком відторгнення, пам'яттю v8, перевантаженою максимумом, дозволеним 1,7 Гб, чи ваш UX залишається задовільним, коли цикл подій часто блокується? для вирішення цього питання я написав, хаосний вузол (альфа), який надає всілякі хаотичні дії, пов'язані з Вузлом

В іншому випадку: без втечі сюди, закон Мерфі торкнеться вашого виробництва без милості

Застосування правильного прикладу: Хаод вузла може генерувати всілякі приводи Node.js, щоб ви могли перевірити, наскільки стійкість вашого додатка до хаосу

*** Розділ : Вимірювання ефективності випробувань ***

️ 18. Отримайте достатньо покриття для впевненості, ~ 80%, здається, є вдалим числом

Робіть: мета тестування - отримати достатню впевненість у швидкому переміщенні, очевидно, чим більше кодів тестується, тим впевненіше може бути команда. Покриття - це показник того, скільки рядків коду (та гілок, висловлювань тощо) тестується. Так скільки вистачить? 10-30%, очевидно, занадто низькі, щоб мати сенс щодо правильності побудови, з іншого боку 100% - це дуже дорого і може перенести фокус від критичних шляхів до екзотичних куточків коду. Довга відповідь полягає в тому, що це залежить від багатьох факторів, таких як тип програми - якщо ви будуєте Airbus A380 наступного покоління, на 100% потрібно, для веб-сайту мультфільмів на 50% може бути занадто багато. Хоча більшість любителів тестування стверджує, що правильний поріг покриття є контекстуальним, більшість із них також згадує число 80% як великий палець правила (Фаулер: «у верхніх 80-х чи 90-х»), який, імовірно, повинен задовольняти більшість програм .

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

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

☺ Приклад: типовий звіт про покриття

Звіт про висвітлення в Стамбулі

Right Як правильно робити приклад: Налаштування покриття на компонент (за допомогою Jest)

Контекстуальне висвітлення

️ 19. Перевірте звіти про покриття, щоб виявити неперевірені ділянки та інші дивацтва

Робити: Деякі проблеми підкрадаються просто під радари, і їх дуже важко знайти, використовуючи традиційні інструменти. Це насправді не помилки, але більше дивного поведінки додатків, які можуть мати серйозний вплив. Наприклад, часто деякі кодові місця ніколи не використовуються або рідко - ви думали, що клас "PricingCalculator" завжди встановлює ціну товару, але виявляється, що насправді ніколи не застосовується, хоча у нас в БД є 10000 продуктів і багато продажів ... Покриття коду звіти допоможуть вам зрозуміти, чи поводиться програма так, як ви вважаєте, що це робить. Крім цього, він також може виділити, які типи коду не перевіряються. Повідомлення про тестування 80% коду не означає, чи охоплені критичні частини. Створення звітів просте - просто запустіть додаток у виробництві чи під час тестування з відстеженням покриття, а потім побачите кольорові звіти, які підкреслюють частоту виклику кожної області коду. Якщо ви знайдете свій час, щоб зазирнути в ці дані - можливо, ви знайдете якісь дітки

В іншому випадку: якщо ви не знаєте, які частини коду залишилися не перевіреними, ви не знаєте, звідки можуть виникнути проблеми

Example Приклад анти-візерунка: що не так у цьому звіті про покриття? На основі сценарію реального світу, де ми відстежували використання нашої програми в QA та з'ясовували цікаві схеми входу (Підказка: кількість відмов входу непропорційна, щось явно не так. Нарешті виявилось, що якась помилка на передній панелі продовжує натискати на API входу в бекенд)

️ 20. Виміряйте логічне покриття за допомогою тестування на мутацію

Робити: Традиційний показник покриття часто бреше: він може показувати вам 100% покриття коду, але жодна з ваших функцій, навіть не одна, не повертає правильну відповідь. Як це? він просто вимірює, над якими рядками коду відвіданий тест, але він не перевіряє, чи тести насправді щось перевіряли - стверджується на правильність відповіді. Як і той, хто подорожує в бізнесі і показує свої паспортні марки - це не підтверджує жодної зробленої роботи, лише те, що він відвідував мало аеропортів та готелів.

Тут використовується мутаційне тестування, щоб допомогти вимірювати кількість коду, який насправді випробовували, а не просто відвідували. Stryker - це бібліотека JavaScript для тестування на мутації, і реалізація дуже акуратна:

(1) він навмисно змінює код і "рослини помилки". Наприклад, код newOrder.price === 0 стає newOrder.price! = 0. Ці «помилки» називаються мутаціями

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

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

В іншому випадку: вам доведеться обдурити, що 85% покриття означає, що ваш тест виявить помилки у 85% вашого коду

Example Приклад антитіла: 100% покриття, 0% тестування

Зробити це правильно Приклад: звіти Stryker, інструмент для тестування на мутації, виявляє та підраховує кількість коду, який не перевіряється (мутації)

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

*** Розділ : ІС та інші заходи якості ***

️ 21. Збагатіть ваші лінери та скасуйте конструкції, які мають проблеми з підв’язкою

Зробіть: Лінери - це безкоштовний обід, з 5-хвилинною установкою ви отримуєте безкоштовний автопілот, що охороняє ваш код і вирішує значну проблему під час введення. Пройшли дні, коли лінінг стосувався косметики (жодних напівколонок!). В даний час Лінтери можуть вирішувати важкі проблеми, такі як помилки, які не викидаються правильно та втрачають інформацію. Окрім вашого основного набору правил (наприклад, стандарт ESLint або стиль Airbnb), подумайте про включення деяких спеціалізованих лінерів, таких як eslint-plugin-chai-очікувати, які можуть виявити тести без тверджень, eslint-plugin-обіцянки можуть виявити обіцянки без вирішення (ваш код ніколи не буде продовжуватися), eslint-plugin-безпека, яка може виявити нетерплячі вирази виразів, які можуть використовуватися для DOS-атак, і eslint-plugin-you-dont-need-lodash-underscore здатна насторожити, коли код використовує методи бібліотеки утиліт які є частиною основних методів V8, таких як Lodash._map (…)

В іншому випадку: розгляньте дощовий день, коли ваше виробництво постійно виходить з ладу, але в журналах не відображається слід стека помилок. Що трапилось? Ваш код помилково кинув об’єкт без помилок, і слід стека було втрачено, що є вагомою причиною для удару головою об цегляну стіну. Налаштування лінійки на 5 хв може виявити цей TYPO і врятувати ваш день

Example Приклад антитіла: Неправильний об'єкт Error викинуто помилково, для цієї помилки не з’явиться слід стека. На щастя, ESLint ловить чергову помилку виробництва

Неправильний об'єкт Error викинуто помилково, для цієї помилки не з’явиться слід стека. На щастя, ESLint ловить наступну помилку виробництва

️ 22. Скоротіть цикл зворотного зв’язку з місцевим розробником-CI

Чи роблять: Використання КІ з блискучими перевірками якості, такими як тестування, зв'язування, перевірка вразливості тощо? Допоможіть розробникам запустити цей конвеєр також локально, щоб вимагати миттєвого зворотного зв’язку та скоротити цикл зворотного зв’язку. Чому? ефективний процес тестування складає багато ітеративних циклів: (1) випробування -> (2) зворотний зв'язок -> (3) рефактор. Чим швидше зворотний зв'язок, тим більше ітерацій вдосконалення розробник може виконувати за модулем та вдосконалювати результати. З іншого боку, коли зворотній зв'язок запізниться на зменшення кількості покращених ітерацій в один день, команда може вже перейти до іншої теми / завдання / модуля і може не підходити до вдосконалення цього модуля.

Практично деякі постачальники CI (Приклад: CLI завантажують CLI) дозволяють запускати трубопровід локально. Деякі комерційні інструменти, такі як wallaby, надають високоцінні і тестуючі уявлення як прототип розробника (без належності). Крім того, ви можете просто додати скрипт npm до package.json, який виконує всі команди якості (наприклад, тест, вказівка, вразливості) - використовувати такі інструменти, як одночасно для паралелізації та ненульового коду виходу, якщо один із інструментів не вдався. Тепер розробник повинен просто викликати одну команду - напр. "Якість запуску npm" - для отримання миттєвого зворотного зв'язку. Розгляньте також питання про скасування зобов’язання, якщо перевірка якості не вдалася за допомогою джетхука (хаскі може допомогти)

В іншому випадку: Коли результати якості надійдуть на наступний день після коду, тестування не стане вільною частиною розвитку, а не офіційним артефактом

Зробити це правильно Приклад: сценарії npm, які виконують перевірку якості коду, усі запускаються паралельно на вимогу або коли розробник намагається висунути новий код

Perform 23. Проведіть тестування e2e над справжнім дзеркалом виробництва

Testing Зробіть: тестування в кінці (e2e) - це головне завдання кожного конвеєра CI - створення однакового ефемерного дзеркала для виробництва з ходу за допомогою усіх відповідних хмарних сервісів може бути втомливим і дорогим. Пошук найкращого компромісу - це ваша гра: Docker-compose дозволяє створювати ізольоване докерізоване середовище з однаковими контейнерами за допомогою одного простого текстового файлу, але технологія резервного копіювання (наприклад, мережа, модель розгортання) відрізняється від реального виробництва. Ви можете комбінувати його з "AWS Local", щоб працювати з заглушкою реальних служб AWS. Якщо ви перейшли на безмежні сервери безлічі фреймів, таких як без сервера, і AWS SAM дозволяє локально викликати код Faas.

Величезна екосистема Kubernetes ще не формалізує стандартний зручний інструмент для місцевого дзеркального відображення та CI, хоча часто нові інструменти запускаються. Один із підходів - це використання «мінімізованих кубернетів», використовуючи такі інструменти, як Minikube та MicroK8, які нагадують справжню річ, лише з меншими накладними витратами. Інший підхід - це тестування на віддаленому "реальному кубернеті", деякі постачальники програм CI (наприклад, Codefresh) мають вбудовану інтеграцію з середовищем Kubernetes і полегшують запуск конвеєра CI по реальній справі, інші дозволяють користувацьким сценаріям проти віддалених Kubernetes.

В іншому випадку: Використання різних технологій виробництва та тестування вимагає підтримання двох моделей розгортання, а розробники та команда ops відокремлюються

Приклад: трубопровід CI, який генерує кластер Kubernetes на ходу (Кредит: Динамічні середовища Kubernetes)

розгортати:
етап: розгортання
зображення: register.gitlab.com/gitlab-examples/kubernetes-deploy
сценарій:
- ./configureCluster.sh $ KUBE_CA_PEM_FILE $ KUBE_URL $ KUBE_TOKEN
- kubectl створення ns $ NAMESPACE
- kubectl створити секрет -n $ NAMESPACE docker-register gitlab-register --docker-server = "$ CI_REGISTRY" --docker-username = "$ CI_REGISTRY_USER" --docker-password = "$ CI_REGISTRY_PASSWORD" --docker-email = "$ GITLAB_USER_EMAIL"
- mkdir .генерований
- відлуння "$ CI_BUILD_REF_NAME- $ CI_BUILD_REF"
- sed -e "s / TAG / $ CI_BUILD_REF_NAME- $ CI_BUILD_REF / g" шаблони / сделки.yaml | трійник ".генерований / угод.ямл"
- застосувати kubectl - простір імен $ NAMESPACE -f .generated / deal.yaml
- застосувати kubectl --pace names $ NAMESPACE -f шаблони / my-sock-shop.yaml
середовище:
назва: тест-для-ci

️ 24. Паралелізуйте виконання тесту

Робіть: коли все правильно, тестування - ваш друг 24/7, який забезпечує майже миттєвий зворотній зв'язок. На практиці виконання тестування 500 одиниць, обмежених процесором, на одному потоці може зайняти занадто багато часу. На щастя, сучасні тестові бігуни та платформи CI (такі як Jest, AVA та Mocha розширення) можуть паралельно провести тест на декілька процесів та досягти значного покращення часу зворотного зв'язку. Деякі виробники CI також паралелізують тести через контейнери (!), Що ще більше скорочує цикл зворотного зв'язку. Незалежно від локальних процесів чи над якимись хмарними CLI з використанням декількох машин - паралелізація попиту, зберігаючи тести автономними, оскільки кожен може працювати на різних процесах

В іншому випадку: отримання результатів тесту через 1 годину після натискання нового коду, оскільки ви вже кодуєте наступні функції, - чудовий рецепт зробити тестування менш релевантним

Як правильно це зробити. Приклад: паралельно Mocha & Jest легко перевершити традиційну Mocha завдяки тестовій паралелізації (Кредит: Тест JavaScript-тестувальників JavaScript)

️ 25. Утримуйтесь від юридичних питань, використовуючи перевірку ліцензії та плагіату

Чи: Проблеми з ліцензуванням та плагіатом зараз, мабуть, не є вашою основною проблемою, але чому б не поставити галочку за 10 хвилин? Купу пакетів npm, таких як перевірка ліцензії та перевірка плагіату (комерційний з безкоштовним планом), можна легко запустити у ваш конвеєр CI та перевірити на наявність смуток, як залежностей із обмежувальними ліцензіями або кодом, який було скопійовано з Stackoverflow і, очевидно, порушує деякі авторські права

В іншому випадку: ненавмисно розробники можуть використовувати пакети з невідповідними ліцензіями або скопіювати комерційний код і зіткнутися з юридичними проблемами

Example Як правильно це зробити:

// встановити перевірку ліцензій у вашому середовищі CI або також локально
npm install -g перевірка ліцензій
// Попросіть його сканувати всі ліцензії і не вдасться вийти з кодом виходу, відмінним від 0, якщо він виявив несанкціоновану ліцензію. Система CI повинна наздогнати цей збій і зупинити збірку
ліцензійна перевірка - підсумок --failO BSD

️26. Постійно перевіряйте, чи є вразливі залежності

Робити: Навіть найбільш авторитетні залежності, такі як Express, знають уразливості. Це можна легко приручити за допомогою інструментів спільноти, таких як npm-аудит, або комерційних інструментів, таких як snyk (пропонуйте також безкоштовну версію спільноти). І те й інше можна викликати у вашому CI під час кожного складання

В іншому випадку: для збереження вашого коду від вразливості без спеціальних інструментів потрібно буде постійно слідкувати за онлайн-публікаціями про нові загрози. Досить стомлюючий

Приклад: результати аудиту NPM

️ 27. Автоматизація оновлень залежності

Зробіть: остання введення пакету-lock.json представила пряжу та пнм (серйозна проблема) (дорога до пекла прокладена добрими намірами) - за замовчуванням пакети вже не отримують оновлень. Навіть команда, яка працює з багатьма свіжими розгортаннями з функцією "npm install" та "npm update", не отримає нових оновлень. Це призводить до версій пакетів, залежних від підпарів, у кращому випадку або до вразливого коду в гіршому випадку. Зараз команди покладаються на репутацію та пам'ять розробників, щоб вручну оновити package.json або використовувати такі інструменти, як ncu, вручну. Більш надійним способом може бути автоматизація процесу отримання найнадійніших версій залежностей, хоча немає срібних рішень для кулі, але є дві можливі дороги автоматизації: (1) CI може провалити побудови, які мають застарілі залежності - використовуючи такі інструменти, як 'npm застарілі 'або' npm-check-updates (ncu) '. Це зробить змушує розробників оновлювати залежності. (2) Використовуйте комерційні інструменти, які сканують код і автоматично надсилають запити на тягу з оновленими залежностями. Залишилося одне цікаве питання, якою має бути політика оновлення залежності - оновлення кожного патчу створює занадто багато накладних витрат, а оновлення права, коли виходить основний, може вказувати на нестабільну версію (багато пакунків, виявлених вразливими в перші дні після звільнення, див. інцидент еслінт-сфери). Ефективна політика оновлення може дозволити деякий "період перевірки" - нехай код буде відставати від @latest на деякий час та версії, перш ніж вважати локальну копію застарілою (наприклад, локальна версія 1.3.1 та версія сховища 1.3.8)

В іншому випадку: у вашій виробництві будуть запущені пакети, які їх автор чітко позначив як ризиковані

Приклад: ncu можна використовувати вручну або в конвеєрі CI, щоб виявити, в якій мірі код відстає від останніх версій

️ 28. Інші поради, що стосуються ІС, не пов'язані з Вузлами

Виконайте: Ця публікація зосереджена на порадах щодо тестування, які стосуються або принаймні можуть бути пояснені з допомогою Node JS. Однак ця куля об'єднує декілька підказок, що не стосуються Вузла, які добре відомі

  1. Використовуйте декларативний синтаксис. Це єдиний варіант для більшості постачальників, але старіші версії Jenkins дозволяють використовувати код або інтерфейс користувача
  2. Виберіть постачальника, який має вбудовану підтримку Docker
  3. Невдача рано, спочатку запустіть найшвидші тести. Створіть крок / рубіж "Тестування на дим", який об'єднує декілька швидких перевірок (наприклад, підключення, тестові одиниці) та надає швидкий зворотний зв'язок до виконавця коду
  4. Спростіть прокручування всіх артефактів, включаючи звіти про випробування, звіти про покриття, звіти про мутації, журнали тощо
  5. Створіть кілька трубопроводів / завдань для кожної події, повторно використовуйте кроки між ними. Наприклад, налаштуйте завдання для філій функції філій та іншого для головного PR. Дозвольте кожній логіці повторного використання, використовуючи спільні кроки (більшість постачальників надають певний механізм повторного використання коду
  6. Ніколи не вкладайте секрети в декларацію про роботу, не захоплюйте їх із секретного магазину чи з конфігурації завдання
  7. Явно нарікають версію в збірці випуску або принаймні переконують, що розробник це зробив
  8. Створіть лише один раз і виконайте всі перевірки над єдиним артефактом збірки (наприклад, зображення Docker)
  9. Тестуйте в ефемерному середовищі, яке не переносить стан між складами. Кешування node_modules може бути єдиним винятком

Інакше: вам не вистачить років мудрості

️ 29. Складіть матрицю: виконайте ті самі кроки CI, використовуючи кілька версій вузла

Робити: Перевірка якості стосується серйозності, чим більше ви охоплюєте удачу, тим швидше виявляєте проблеми. Розробляючи пакети для багаторазового використання або виконуючи виробництво для багатьох клієнтів з різною конфігурацією та версіями Node, CI повинен виконати конвеєр тестів для всіх перестановок конфігурацій. Наприклад, якщо припустити, що ми використовуємо mySQL для одних клієнтів, а Postgres для інших - деякі постачальники CI підтримують функцію під назвою "Матриця", яка дозволяє запускати костюм тестування проти всіх перестановок mySQL, Postgres та декількох версій вузла, таких як 8, 9 і 10. Це робиться за допомогою конфігурації лише без додаткових зусиль (якщо припустимо, що у вас є тестування чи будь-які інші перевірки якості). Інші CI, які не підтримують Matrix, можуть мати розширення або налаштування, щоб це дозволити

В іншому випадку: Отже, виконавши всю цю важку роботу з написання тестування, ми збираємось дозволити помилкам прокрадатись лише через проблеми з конфігурацією?

☺ Приклад: Використання визначення збірки Travis (постачальник CI) для запуску одного і того ж тесту для кількох версій вузла

мова: node_js
node_js:
  - "7"
  - "6"
  - "5"
  - "4"
встановити:
  - встановити npm
сценарій:
  - тест запуску npm

Спасибі. Інші статті, які вам можуть сподобатися

  • Контрольний список: кращі практики виробництва Node.js (серпень 2018 року)
  • 19 способів стати кращим розробником Node.js у 2019 році
  • Найкращі практики безпеки Node.js (вересень 2018 року)
  • YouTube: 5 передових і блискучих методик тестування
  • Найкращі практики Node.js - 79 найкращих практик для надійної програми Node

Хочете більше? слідкуйте за мною у Twitter

У вас є власна порада для тестування? PR тут, і я обов’язково оновлю цю статтю