Як ви виявляєте проблеми залежності залежними тестами під час використання макетних об'єктів?


98

У вас є клас X, і ви пишете деякі одиничні тести, які підтверджують поведінку X1. Існує також клас A, який приймає X як залежність.

Коли ви пишете одиничні тести для A, ви знущаєтесь з X. Іншими словами, під час тестування одиниці A ви встановлюєте (постулюєте) поведінку макету X як X1. Час йде, люди користуються вашою системою, потребують змін, X розвивається: ви модифікуєте X, щоб показати поведінку X2. Очевидно, що одиничні тести для X не вдасться, і вам потрібно буде їх адаптувати.

Але що з А? Одиничні тести на A не пройдуть, коли поведінка X зміниться (через глузування з X). Як виявити, що результат A буде іншим, коли буде запущено "реальний" (модифікований) X?

Я очікую відповідей у ​​рядку: "Це не мета одиничного тестування", але яке значення має одиничне тестування? Чи справді це лише говорить вам про те, що коли всі тести проходять, ви не внесли переломних змін? І коли поведінка класу змінюється (охоче чи небажання), як ви можете виявити (бажано, в автоматизованому вигляді) всі наслідки? Чи не слід більше зосереджуватися на інтеграційному тестуванні?



36
На додаток до всіх запропонованих відповідей, я мушу сказати, що я приймаю питання із наступним твердженням: "Чи дійсно це лише говорить вам про те, що коли всі тести проходять, ви не внесли переломних змін?" Якщо ви справді думаєте, що зняти страх перед рефакторингом
малоцінно

5
Тестування блоку повідомляє, чи поводиться ваша одиниця коду так, як ви цього очікували. Ні більше, ні менше. Макети та тестові дублери надають вам штучне, контрольоване середовище для здійснення своєї одиниці коду (ізольовано), щоб побачити, чи відповідає вона вашим очікуванням. Ні більше, ні менше.
Роберт Харві

2
Я вважаю, що ваше приміщення невірно. Коли ви згадуєте, X1ви говорите, що Xреалізує інтерфейс X1. Якщо ви зміните інтерфейс X1на X2макет, який ви використовували в інших тестах, більше не слід збирати, отже, ви також змушені виправити ці тести. Зміни в поведінці класу не повинні мати значення. Насправді, ваш клас Aне повинен залежати від деталей реалізації (що саме ви змінили б у цьому випадку). Тож одиничні тести для роботи Aвсе ще правильні, і вони говорять про те, що Aпрацює в ідеальній реалізації інтерфейсу.
Бакуріу

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

Відповіді:


125

Коли ви пишете одиничні тести для A, ви знущаєтесь з X

Чи ти? Я цього не роблю, якщо мені абсолютно не доведеться. Я повинен, якщо:

  1. X повільно, або
  2. X має побічні ефекти

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

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

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


94
@Laiv, Ні, одиничні тести повинні діяти як одиниці, тобто виконуватись ізольовано, від інших тестів . Вузли та графіки можуть здійснити похід. Якщо я можу за короткий час провести ізольований тест без побічних ефектів, це єдиний тест. Якщо це визначення вам не подобається, назвіть це автоматизованим тестом і припиніть писати тести на лайно, щоб відповідати дурній семантиці.
Девід Арно

9
@DavidArno На жаль, існує дуже широке визначення ізольованого. Дехто хотів би, щоб "одиниця" включала середній рівень та базу даних. Вони можуть вірити, що їм подобається, але шанси на те, що при розробці будь-якого розміру колеса зійдуть в досить короткому порядку, оскільки менеджер збірки викине це. Як правило, якщо вони відокремлені від складання (або еквівалента), це добре. Зверніть увагу: якщо ви кодуєте інтерфейси, то набагато простіше додати глузування та DI пізніше.
Роббі Ді

13
Ви виступаєте за тестування іншого типу, а не для того, щоб відповідати на питання. Це справедливий момент, але це досить непомітний спосіб зробити це.
Філ Мороз

17
@PhilFrost, щоб процитувати себе: " І якщо хтось із вас засмучується, називаючи ці тести" одиничними тестами ", тоді просто називайте їх" автоматизованими тестами "і продовжуйте писати хороші автоматизовані тести. " Пишіть корисні тести, а не дурні тести які просто відповідають якомусь випадковому визначенню слова. Або ж прийміть, що, можливо, у вас неправильне визначення поняття «одиничний тест», і ви перестали використовувати макети, тому що ви помилилися. У будь-якому випадку, ви закінчите кращі тести.
Девід Арно

30
Я з цим @DavidArno на цьому; моя стратегія тестування змінилася після перегляду цієї розмови від Ian Cooper: vimeo.com/68375232 . Щоб звести його до одного речення: Не перевіряйте заняття . Тест поведінки . Ваші тести не повинні мати знань про внутрішні класи / методи, що використовуються для реалізації бажаної поведінки; вони повинні знати лише публічну поверхню вашого API / бібліотеки, і вони повинні перевірити це. Якщо тести мають занадто багато знань, то ви тестуєте деталі впровадження, і ваші тести стають крихкими, поєднаними з вашою реалізацією, а насправді є просто якорем на шиї.
Річібан

79

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

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

Для одиничних тестів вам потрібно лише 20 одиничних тестів + ​​1 інтеграційний тест, щоб повністю охопити всі випадки.

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

Ось дуже хороше відео про недоліки покладатися лише на інтеграційні тести JB Rainsberger Integrated Tests - це афера HD


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

16
Правильно, але ніде тест на 20 одиниць не вимагає глузування. Якщо у вас є 10 тестів на A, які охоплюють усі A, і 10 ваших тестів, які охоплюють весь B, а також повторно тестують 25% A як бонус, це здається між «чудовим» і хорошим. Знущання над тестами A в Bs видається активно нерозумним (якщо насправді немає причини, чому A є проблемою, наприклад, це база даних або вона містить багато іншого)
Річард Тінгл

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

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

1
@MatthieuM. Я стверджую, що це виходить за межі тестування одиниць. Код клею може бути перевірений одиницею, тоді як взаємодія між A і B через код клею є інтеграційним тестом. При виявленні конкретних крайових випадків або помилок їх можна додати до тестів коду клею та остаточно перевірити в інтеграційному тестуванні.
Ендрю Т Фіннелл

72

Коли ви пишете одиничні тести для A, ви знущаєтесь з X. Іншими словами, під час тестування одиниці A ви встановлюєте (постулюєте) поведінку макету X як X1. Час йде, люди користуються вашою системою, потребують змін, X розвивається: ви модифікуєте X, щоб показати поведінку X2. Очевидно, що одиничні тести для X не вдасться, і вам потрібно буде їх адаптувати.

Вуха, почекай хвилинку. Наслідки тестів для відмови X надто важливі, щоб таким чином змалювати.

Якщо зміна реалізації X з X1 на X2 порушує одиничні тести для X, це вказує на те, що ви внесли назад несумісну зміну в контракт X.

У сенсі Ліскова X2 не є X, тому вам слід подумати про інші способи задоволення потреб своїх власників акцій (наприклад, введення нової специфікації Y, реалізованої X2).

Детальнішу інформацію див. У розділі Пітер Гіньєнс: Кінець версій програмного забезпечення або Rich Hickey Simple Made Easy .

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

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

Іноді ви побачите це відмінність, виражене як одиночні випробування проти sociableтестів; див. поля Джея, що працюють ефективно з одиничними тестами .

Чи не слід більше зосереджуватися на інтеграційному тестуванні?

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

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


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

1
"без ізольованих / одиночних випробувань, що застосовують тиск на конструкцію, якість погіршується". Я думаю, що це важливий момент. Поряд з перевірками поведінки, одиничні тести мають побічний ефект, щоб змусити вас мати більш модульний дизайн.
MickaëlG

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

15

Почніть з того, що основна передумова питання є хибною.

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

Якщо у мене справжній клас X, який реалізує інтерфейс X1, я можу написати макет XM, який також відповідає X1. Тоді мій клас A повинен використовувати щось, що реалізує X1, що може бути класом X або глузувати з XM.

Тепер, припустимо, ми змінюємо X, щоб реалізувати новий інтерфейс X2. Ну, очевидно, мій код більше не збирається. A потрібно щось, що реалізує X1, а цього більше не існує. Проблема виявлена ​​та може бути виправлена.

Припустимо, замість заміни X1 ми просто модифікуємо його. Тепер клас А все налаштовано. Однак макет XM більше не реалізує інтерфейс X1. Проблема виявлена ​​та може бути виправлена.


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

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


11
Ця відповідь робить безліч припущень, які не повинні виконувати. По-перше, це передбачає, що ми перебуваємо в C # або Java (або, точніше, що ми перекладені мовою, що мова має інтерфейси, і що X реалізує інтерфейс; жодне з них не повинно бути правдою). По-друге, воно передбачає, що будь-яка зміна поведінки або "контракту" X вимагає змін інтерфейсу (як розуміє компілятор), який реалізує X. Це, очевидно, не вірно, навіть якщо ми перебуваємо на Java або C #; ви можете змінити реалізацію методу, не змінюючи його підпису.
Марк Амері

6
@MarkAmery Це правда, що термінологія "інтерфейсу" є більш специфічною для C # або Java, але я думаю, що суть полягає у припущенні певного "контракту" поведінки (а якщо це не кодифіковане, то автоматичне виявлення цього неможливо). Ви також абсолютно правильні, що імплементацію можна змінити без зміни договору. Але зміна впровадження без зміни інтерфейсу (або контракту) не повинно впливати на будь-якого споживача. Якщо поведінка A залежить від того, як реалізується інтерфейс (або контракт), неможливо (змістовно) тестувати одиницю.
Влад274

1
"Ви також абсолютно правильні, що імплементацію можна змінити без зміни договору" - хоча це також правда, це не те, що я намагався зробити. Швидше за все, я стверджую різницю між контрактом (розуміння програмістом того, що повинен робити об'єкт, можливо, зазначено в документації) та інтерфейсом (перелік підписів методу, зрозумілим компілятором) і кажу, що контракт може змінюватись без зміни інтерфейсу. Всі функції з однаковою підписом є взаємозамінними з точки зору системи типу, але насправді не!
Марк Амері

4
@MarkAmery: Я не думаю, що Влад використовує слово "інтерфейс" у тому ж сенсі, як ви його використовуєте; як я читаю відповідь, мова йде не про інтерфейси у вузькому сенсі C # / Java (тобто набір методів підписів), а в загальному сенсі цього слова, як використовується, наприклад, в термінах "інтерфейс програмування додатків" або навіть " користувацький інтерфейс". [...]
Ільмарі Каронен

6
@IlmariKaronen Якщо Влад використовує "інтерфейс", щоб означати "контракт", а не у вузькому сенсі C # / Java, то висловлювання "Тепер припустимо, що ми змінимо X для реалізації нового інтерфейсу X2. Ну, очевидно, мій код більше не компілюється. " це просто неправда, оскільки ви можете змінити контракт, не змінюючи жодного методу підписів. Але чесно кажучи, я думаю, що проблема тут полягає в тому, що Влад не використовує ані сенс послідовно, а конфузує їх - ось що веде вниз по твердженню, що будь-яка зміна договору X1 обов'язково призведе до помилки компіляції, не помічаючи , що це помилково .
Марк Амері

9

Запитання по черзі:

яке значення має одиничне тестування

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

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

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

І коли поведінка класу змінюється (охоче чи небажання), як можна виявити (бажано, автоматизованим чином) усі наслідки

Більше тестування - хоча інструменти стають все кращими та кращими. Але ви повинні визначати поведінку класу в інтерфейсі (див. Нижче). Зверніть увагу: на піраміді тестування завжди знайдеться місце для ручного тестування.

Чи не слід більше зосереджуватися на інтеграційному тестуванні?

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

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

Якщо ви хочете переконатися, що клас А споживає клас X таким же чином, вам слід використовувати інтерфейс, а не конкремент. Тоді, швидше за все, можливі зміни в процесі компіляції.


9

Це правильно.

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

Блок тестів не існує, щоб перевірити, чи працює вся програма.

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

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

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

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


2

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

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


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

7
@RobbieDee Я здогадуюсь, він мав на увазі, що під час тестування fac(5) == 120ви не довели, що fac()дійсно повертає фактичний аргумент. Ви лише довели, що fac()повертаєте факторіал з п'яти, коли проходите 5. І навіть це не напевно, як fac()можна було б 42замість цього повернутися в перші понеділки після повного затемнення в Тімбукту ... Проблема тут полягає в тому, що ви не можете довести відповідність, перевіривши окремі вхідні тести, вам потрібно буде перевірити всі можливі дані, а також доведіть, що ви не забули жодного (наприклад, читання системного годинника).
cmaster

1
@RobbieDee Тести (включаючи одиничні тести) - це погана заміна, найчастіше найкраща в наявності для реальної мети, перевірена машиною доказ. Розглянемо весь простір стану досліджуваних одиниць, включаючи простір стану будь-яких компонентів або макетів у них. Якщо у вас дуже обмежений простір станів, тести не можуть охопити цей простір станів. Повне покриття було б доказом, але це доступно лише для крихітних просторів стану, наприклад, тестування одного об'єкта, що містить один мутаційний байт або 16-бітове ціле число. Автоматизовані докази набагато цінніші.
Френк Хілеман

1
@cmaster Ви дуже добре підсумували різницю між тестом та доказом. Дякую!
Френк Хілеман

2

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

Мені кращою стратегією є гарне розмежування проблем (наприклад, ви можете протестувати частину програми свого додатку, не вводячи частини B до Z). Така хороша архітектура справді допомагає написати хороший тест.

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

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


1

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

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

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

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

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

Однак впровадження нової поведінки зовсім не повинно компрометувати систему. Linux та інші рясніють застарілими функціями. І такі речі, як конструктори (та методи), можуть щасливо перевантажуватися, не змушуючи весь код виклику змінюватися.

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


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

0

Якщо інтерфейс для X не змінився, вам не потрібно змінювати тест одиниці на A, оскільки нічого, пов'язане з A, не змінилося. Здається, ви справді написали одиничний тест X і A разом, але назвали це одиничним тестом A:

Коли ви пишете одиничні тести для A, ви знущаєтесь з X. Іншими словами, під час тестування одиниці A ви встановлюєте (постулюєте) поведінку макету X як X1.

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

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

Тож, можливо, X спочатку повертав відсортовані дані по понеділках та порожні списки по вівторках. Але тепер, коли X повертає несортовані дані по понеділках і викидає винятки по вівторках, A це не байдуже - ці сценарії вже були охоплені в тесті блоку A.


Що робити, якщо X щойно перейменований індекс у поверненому масиві з foobar в foobarRandomNumber, як я можу порахувати з цим? якщо ви зрозумієте мою думку, це в основному моя проблема, я перейменував повернений стовпець з secondName на прізвище, класичне завдання, але мій тест ніколи не дізнається, оскільки його знущалися. У мене просто таке дивне відчуття, ніби багато людей з цього питання ніколи насправді не пробували щось подібне, перш ніж коментувати
FantomX1

Компілятор повинен був виявити цю зміну і дав вам помилку компілятора. Якщо ви використовуєте щось на зразок Javascript, я рекомендую або перейти на Typescript, або використовувати компілятор типу Babel, який може виявити цей матеріал.
Диск Moby

Що робити, якщо я використовую масиви в PHP, або в Java, або в Javascript, якщо ви зміните індекс масиву або видалите його, хтось із цих компіляторів мов розповість вам про це, індекс може бути вкладений у 36-й - продуманий номер вкладений рівень масиву, тому я думаю, що компілятор не є рішенням для цього.
FantomX1

-2

Ви повинні подивитися на різні тести.

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

Дійсно, A повинен насміхатися з X для своїх одиничних тестів, а тест з Mock повинен проходити навіть після того, як ви його зміните.

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

Крім того, якщо X потребує нової поведінки, було б краще запропонувати новий метод, який забезпечить бажаний результат

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