Пишіть тести. Не забагато. Не замало. Переважно інтеграційні

15 липня, 2020
Обкладинка статті

Фото від Elena Cordery

Я робив доповідь на основі цієї публікації яку можна подивитись тут:

Нещодавно, Ґільєрмо Рауч (творець Socket.io та засновник Zeit.co (компанії що стоїть за масою виняткових речей що виходили останнім часом)) твітнув щось фундаментальне:

Пишіть тести. Не замало. Не забагато. Переважно інтеграційні

Це глибоко, хоч і коротко, отже вйо до деталей:

Пишіть тести

Так, для більшості проєктів вам слід писати автоматичні тести. Слід, якщо ви хоч трохи цінуєте свій час. Набагато краще спіймати ваду локально тестами ніж приймати дзвінок о 2:00 ранку і тоді виправляти її. Я відчуваю що економлю час коли працюю над написанням тестів. Це може зайняти або ж не займати більше часу, аніж розробка, проте я (та інші) майже напевно заощаджуватимуть час підтримуючи їх.

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

Не забагато

Я чув, що менеджери та команди вимагають 100%-ве покриття коду тестам. Це дуже погана ідея. Проблема полягає в тому що віддача від тестів спадає як тільки покриття перевищує 70% (Я видумав це число... жодного наукового підґрунтя в ньому нема). Чому так? Ну коли ви прагнете до 100% увесь час то виявляєте, що проводите час тестуючи речі які насправді тестувати не потрібно. Речей які фактично взагалі не містять логіки (а отже будь-які вади можуть спіймати ESLint та Flow). Підтримка таких тестів дійсно дуже сповільнює вас та вашу команду.

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

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

Переважно інтеграційні

Існують всілякі різноманітні типи тестування (зацініть мою 5-хвилинну доповідь про це на Fluent Conf: "Що можна дізнатися про тестування від колеса"). У кожного з них є свої компроміси. Три найпоширеніші форми тестування, про які ми говоримо, коли йдеться про автоматизоване тестування, це: unit, інтеграційне та E2E.

Ось слайд з мого воркшопу для FrontendMasters: "Тестування JavaScript додатків".

Піраміда тестування

Ця піраміда тестування — комбінація тієї яку я взяв з блогу Мартіна Фавлера та тієї які я взяв з блогу Google Testing.

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

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

Як зазначено у твіті, наші інструменти вийшли за рамки припущення оригінальної концепції піраміди тестування Мартіна. Ось чому я створив «Кубок тестування» 🏆


Ось інша жартівлива ілюстрація важливості інтеграційних тестів:

Не має значення, чи ваш компонент <A /> відмальовує компонент <B /> з властивостями c і d, якщо компонент <B /> фактично ламається, якщо властивість c не передається. Тож хоча наявність unit-тестів для перевірки роботи компонентів в ізоляції не є поганою річчю, користі від того буде не багато якщо ви також не перевірятимете їх роботу належним чином укупі. І ви помітите, що маючи перевірку на коректну роботу компонентів один з одним, вам часто не потрібно перейматись їх тестуванням в ізоляції.

Інтеграційні тести забезпечують чудовий баланс компромісів між впевненістю та швидкістю/витратами. Ось чому бажано витрачати на них більшу частину (не всі, майте на увазі) своїх зусиль.

Докладніше про це читайте у тестуванні деталей реалізації. Додаткову інформацію про різні відмінності тестів можна отримати зі статті про статичне проти unit проти інтеграційного про E2E тестування для фронтенд додатків

Як писати більше інтеграційних тестів

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

Якщо ви працюєте з React, тоді це також включає неглибокий рендеринг. Докладніше про це читайте у Чому я ніколи не використовую неглибокий рендеринг.

Висновок

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

Сподіваюся що цей матеріал стане вам у пригоді, і я бажаю вам успіху у прагненні знайти впевненість у випуску ваших додатків!