Як провести тести?


53

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

Я можу придумати три можливі типи помилок у тестах:

  1. Логічні помилки, коли програміст неправильно зрозумів завдання під рукою, а тести роблять те, що він вважав, що вони повинні зробити, що неправильно;

  2. Помилки в базовій основі тестування (наприклад, протікає глузуюча абстракція);

  3. Помилки в тестах: тест робиться дещо інакше, ніж те, що вважає програміст.

Помилки типу (1), здається, неможливо запобігти (якщо програміст просто ... стає розумнішим). Однак (2) та (3) можуть бути простежувані. Як ви ставитеся до подібних помилок? Чи є у вас якісь спеціальні стратегії, щоб їх уникнути? Наприклад, ви пишете якісь спеціальні "порожні" тести, які перевіряють лише припущення автора тесту? Крім того, як ви підходите до налагодження зламаного тестового випадку?


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

@ Carson63000 Якщо це простий тестовий тест на щось з перевіреним макетом, складність розділена і під контролем (я думаю).
mlvljr

13
Але як тоді ви перевіряєте тестові тести?
окудо

+1. Пункт 1 може бути помилкою вимог. Не можна запобігти лише переглядом вимог. Можливо, з рук програміста, якщо вони також не є вимогами аналітика
MarkJ

@ocodo: Так само, як ви спостерігаєте за Охоронцями. :)
Грег Бургхардт

Відповіді:


18

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

  1. Існує кілька методик, які не дозволяють вам додавати однакову помилку як у вашому коді, так і в тестах:

    1. Клієнт повинен бути іншою людиною, ніж виконавець.
    2. Спочатку напишіть тести, а потім код (наприклад, у Test Driven Development).
  2. Вам не потрібно тестувати базову платформу. Тести не лише виконують написаний вами код, але і запускають код із платформи. Хоча вам не потрібно ловити помилки на тестовій платформі, дуже важко писати код і тести, які завжди приховують помилку на платформі, інакше кажучи, дуже важко мати систематичну помилку як у ваших тестах / коді, так і на платформі, і ймовірність зменшується при кожному створеному вами тесті. Навіть якби ви спробували це зробити, у вас було б дуже важке завдання.

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


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

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

24

Спробуйте зробити індивідуальні тести якомога меншими (короткими).

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

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


3
Що робити, якщо для тестів потрібна досить складна установка? Іноді такі речі не під вашим контролем.
Рішард Шопа

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

Який найкращий спосіб перевірити, чи виконується ця "початкова умова" - це саме питання мого питання. Ви пишете для цього окремий тест? Або просто припустити, що тести порушаться, якщо ця умова не відповідає дійсності? Що з ситуацією, коли налаштування не є «катастрофічно» поганим, лише трохи вимкненим?
Ryszard Szopa

2
Ваші тести повинні провалитись, якщо початкові умови не відповідають правильності, в цьому і полягає вся суть. Перебуваючи в штаті A, ви очікуєте результату B. Якщо у вас немає стану A, тест повинен вийти з ладу. У цей момент ви можете дослідити, чому він не вдався, погані початкові умови чи поганий тест, але він повинен зазнати невдачі в обох випадках. Навіть якщо він не є, як ви говорите, «трохи від" (тобто "A" => "B", "a" => "b", але ніколи "a" => "B"або ваш тест погано).
д-р Ганнібал Лектр

19

Одна з тактик - написати тест перед кодом, який він тестує, і переконатися, що тест спочатку не виходить з правильної причини. Якщо ви використовуєте TDD, ви повинні пройти принаймні цей рівень тестування тестів.

Більш вичерпним способом перевірити якість тестового набору є використання тестування на мутації .


2
І що ваш тест не справляється з правильної причини .
Френк Ширар

@Frank - Так. Я додам це до відповіді.
Дон Робі

І ви додаєте новий тест для нової поведінки, яку потрібно перевірити. Не додавати до існуючих тестів.
Хупернікетес

@DonRoby, Чи вважаєте ви тестування на мутації корисним на практиці? Які недоліки ви виявили у своїх тестових випадках із цим?
dzieciou

4

Для №1 і №3: Тести одиниць не повинні містити ніякої логіки, якщо ви це зробите, то ви, мабуть, випробовуєте більше ніж одне в своєму одиничному тесті. Один найкращий досвід для одиничного тестування - це лише один тест на одиницю випробування.

Перегляньте це відео Роя Ошерове, щоб дізнатися більше про те, як добре писати одиничні тести.


оголошення №3 - Я погоджуюся, що тести повинні бути максимально простими і не повинні містити ніякої логіки. Однак подумайте про етап налаштування тесту, коли ви створюєте об'єкти, які йому знадобляться. Ви можете створити трохи неправильні об'єкти. Це такі проблеми, про які я думаю.
Ryszard Szopa

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

3

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


2

Повинно бути момент, коли слід зупинити спроби одиничного тестування. Слід знати, коли провести лінію. Чи слід писати тестові випадки для перевірки тестових випадків? А як щодо нових тестових випадків, написаних для тестових тестів? Як ми їх перевіримо?

if (0 > printf("Hello, world\n")) {
  printf("Printing \"Hello, world\" failed\n");
}

Редагувати: Оновлено з поясненнями, як запропоновано коментарем.


-1 Що? Це, мабуть, не має жодної актуальності.
альтернатива

2
Повинно бути момент, коли слід зупинити спроби одиничного тестування. Слід знати, коли провести лінію. Чи слід писати тестові випадки для перевірки тестових випадків? Як щодо нових тестових випадків, написаних для тестових тестових випадків? Як ми їх перевіримо?
дім

2
Процес Мозок підняв EInfiniteRecursion під час спроби екстраполяції вашої заяви ...
Мейсон Уілер

Замініть свою відповідь своїм коментарем, і ви отримаєте +1
Зауважте, що потрібно самостійно - придумати ім’я

3
Чесно кажучи, ваш приклад - солом’яний чоловік. Ви тестуєте підсистему printf () у бібліотеці С, а не фактичну програму, яка викликає printf (). Я згоден, однак, що в якийсь момент треба порушити рекурсивне тестування тестів.
Тім Пост

2

Гей.
Ви маєте додатки:

  • Ваш продукт
  • Ваш тест на цей продукт.

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

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

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

Тести перевіряють лише деякі частини програми. Я тестую додаток, тестую тести.


2

Тести не повинні бути достатньо «розумними», щоб ховати помилок.

Код, який ви пишете, реалізує набір специфікацій. (Якщо X, то Y, за винятком випадків Z, у цьому випадку Q, тощо). Всі тести, які слід намагатися виконати, це визначити, що X насправді є Y, якщо тільки Z в цьому випадку Q. Це означає, що все тест повинен робити, це встановити X і перевірити Y.

Але це стосується не всіх випадків, ви, напевно, говорите, і ви матимете рацію. Але якщо ви зробите тест "розумним" достатньо, щоб знати, що X повинен бути лише Y, якщо не Z, то ви в основному повторно реалізуєте бізнес-логіку в тесті. Це проблематично з причин, які ми розберемо трохи глибше нижче. Ви не повинні покращувати покриття коду, зробивши перший тест "розумнішим", замість цього слід додати другий тупий тест, який встановлює X і Z і підтверджує Q. Таким чином, у вас буде два тести, один, який охоплює загальний випадок ( іноді також відомий як щасливий шлях) і той, який охоплює край край як окремий тест.

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

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

TL: DR: Якщо ваші тести потребують тестування, ви робите це неправильно. Пишіть тупі тести .


0

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


0

Коротка відповідь: Виробничий код тестує тести .

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

він же йде на одиничні тести - Якщо тест не вдається, це вказує, що щось не так. Це може бути виробничий код, але це може бути і тестовий код! Ця остання частина, якщо важлива.

Зауважте, що помилки вашого типу (1) неможливо знайти за допомогою тестування одиниць. Щоб уникнути подібних помилок потрібні інші інструменти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.