TDD Red-Green-Refactor і якщо / як перевірити методи, які стають приватними


91

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

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

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

Далі я продовжую функцію "збиратиNonNumericColumns", яка читає файл, по одному рядку, і викликає мою функцію "findNonNumericFields" у кожному рядку, щоб зібрати всі стовпці, які з часом повинні бути видалені. Пару червоно-зелених циклів, і я закінчив, маючи знову робочу функцію і повний тест.

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

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

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

Отже, що робити? Чи TDD (із швидким циклом червоно-зеленого рефактора) просто не сумісний із приватними методами? Або є помилка в моєму дизайні?



2
Або ці два фрагменти функціональності достатньо різні, щоб бути різними одиницями; в цьому випадку приватні методи, ймовірно, повинні бути на власних класах, або вони є тим самим блоком, і в цьому випадку я не розумію, чому ви пишете тести для поведінка внутрішня до підрозділу. Щодо передостаннього абзацу, я не бачу конфлікту. Навіщо вам потрібно написати цілий складний приватний метод, щоб пройти один тестовий випадок? Чому б не вигнати його поступово за допомогою публічного методу або почати з нього вбудовано, а потім витягнути його?
Бен Аронсон

26
Чому люди сприймають ідіоми та кліше з книг та блогів із програмуванням як фактичні вказівки щодо програмування - не в мене.
AK_

7
Мені не подобається TDD саме з цієї причини: якщо ви перебуваєте в новому районі, тоді ви будете робити багато зайвих робіт, намагаючись з’ясувати, якою має бути архітектура та як працюють певні речі. З іншого боку: якщо ви перебуваєте в районі, з яким ви вже відчували себе, тоді вам буде корисно написати тести спочатку, окрім того, як вас дратувати, оскільки intellisense не розуміє, чому ви пишете некомпілюючий код. Я набагато більший шанувальник думати про дизайн, писати його, а потім перевіряти його.
Jeroen Vannevel

1
"Більшість людей, схоже, згодні з тим, що приватні методи не слід перевіряти безпосередньо" - ні, безпосередньо тестуйте метод, якщо це має сенс робити. Сховати це так, privateніби це має сенс робити.
оса

Відповіді:


44

Одиниці

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

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

За цим слід негайно запитати себе "Чи це буде окрема перевіряемая одиниця до gatherNonNumericColumnsтієї чи іншої?"

Якщо відповідь " так, окремо ", то ваш спосіб дії простий: цей метод повинен бути відкритим для відповідного класу, щоб його можна перевірити як одиницю. Ваш менталітет - це щось на кшталт "Мені потрібно випробувати один метод, і мені також потрібно випробувати інший метод"

З того, що ви говорите, ви зрозуміли, що відповідь " ні, частина того ж ". У цей момент у вашому плані більше не повинно бути повного запису та тестування, findNonNumericFields а потім запису gatherNonNumericColumns. Натомість слід просто писати gatherNonNumericColumns. Наразі це findNonNumericFieldsмає бути лише ймовірною частиною пункту призначення, який ви маєте на увазі, коли ви вибираєте черговий тестовий випадок та робите рефакторинг. Цього разу ваш менталітет - «Мені потрібно випробувати один метод, і в той час як я це роблю, я повинен мати на увазі, що моя закінчена реалізація, ймовірно, буде включати цей інший метод».


Тримаючи короткий цикл

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

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

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


Дорожня карта

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


2
Я думаю, що це відповідь саме тут. Приймаючи TDD в середовищі OOP, я часто виявляв, що важко долаю власні інстинкти знизу вгору. Так, функцій має бути мало, але це вже після рефакторингу. Раніше вони можуть бути величезними монолітами. +1
Жоао Мендес

2
@ JoãoMendes Ну, я не впевнений, що вам слід перейти до стану величезного моноліту перед рефакторингом, особливо на дуже коротких циклах RGR. Але так, в межах тестового блоку робота знизу вгору може призвести до проблем, які описує ОП.
Бен Аронсон

1
Гаразд, я думаю, я розумію, куди пішло не так. Дякую всім вам (позначив цю як відповідь, але більшість інших відповідей так само корисні)
Генрік Берг

66

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

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

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

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

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

Хоча я починаю з поняття, що одиниця є класом, я часто беру купу тісно пов'язаних класів і трактую їх як єдину одиницю

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


14
Мені здається, що ця відповідь повністю ігнорує підхід TDD у питанні ОП. Це просто повторення «не відчувають приватні методи» мантри, але це не пояснює , як TDD - що це на самому справі метод , заснований - може працювати з не-методу одиниці на основі тестового підходу.
Doc Brown

6
@DocBrown ні, він відповідає йому повністю, кажучи "не надмірно гранулюй" свої підрозділи та ускладнюй життя собі. TDD не заснований на методі, це на основі одиниць, де одиниця має будь-який сенс. Якщо у вас є бібліотека С, то так, кожен блок буде функцією. Якщо у вас є клас, одиниця є об'єктом. Як каже Фаулер, іноді підрозділ складається з декількох тісно пов'язаних класів. Я думаю, що багато людей вважають тестування одиниць методом за методом просто тому, що деякі немічні інструменти генерують заглушки на основі методів.
gbjbaanb

3
@gbjbaanb: спробуйте запропонувати тест, який дозволяє ОП реалізувати своє "збирати нечислові поля в рядку", використовуючи спочатку чистий TDD, не маючи публічного інтерфейсу класу, який він має намір записати, вже написаного.
Doc Brown

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

7
@Matthew: Його помилка в тому, що він написав функцію в першу чергу. В ідеалі він повинен був написати публічний метод як код спагетті, а потім перефактурувати його в приватну функцію в циклі рефактора - не позначати його як приватний у циклі рефактора.
slebetman

51

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

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

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


Так, я згоден з вами. Але у мене є проблема з вашим першим твердженням, як "досить складною" частиною, так і "достатньо окремою" частиною. Щодо "досить складного": я намагаюся зробити швидкий червоно-зелений цикл, а це означає, що я можу кодувати не більше ніж хвилину або близько того, перш ніж перейти до тестування (або навпаки). Це означає, що мої тести дійсно будуть дуже дрібними. Я подумав, що це одна з переваг TDD, але, можливо, я переборщив, щоб він став недоліком.
Генрік Берг

Щодо "достатньо окремого": я дізнався (знову від дядька), що функції повинні бути невеликими, а також, що вони повинні бути меншими. Так що в основному я намагаюся зробити 3-4 лінійні функції. Тож більш-менш вся функціональність розділена на власні методи, незалежно від того, наскільки вони малі та прості.
Генрік Берг

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

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

@gbjbaanb Я б заперечував, що вони одно і те саме.
RubberDuck

29

Особисто я відчуваю, що ти далеко пішов у реалізацію, коли писав тести. Ви припускали, що вам знадобляться певні методи. Але чи справді вони потрібні, щоб вони робили те, що повинен робити клас? Чи не вдалося б класу, якби хтось прийшов і реконструював їх внутрішньо? Якщо ви використовували клас (і це, на мій погляд, має бути умонастроєм тестера), ви могли б потурбуватися менше, якщо є явний метод перевірки чисел.

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

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


1
"Деталі про реалізацію" - це такі речі, як "чи використовував я XOR або тимчасову змінну для обміну вставками між змінними". Захищені / приватні методи мають договори, як і все інше. Вони беруть участь, працюють з ним і дають певний результат, за певних обмежень. Все, що має договір, в кінцевому підсумку має бути перевірене - не обов'язково для тих, хто споживає вашу бібліотеку, але для тих, хто її підтримує та модифікує після вас. Просто тому , що це не «громадськість» не означає , що вона не є частиною до API.
Кнетик

11

Ви не робите TDD, виходячи з того, що ви очікуєте, що клас буде робити всередині.

Ваші тестові приклади повинні базуватися на тому, що клас / функціональність / програма мають робити із зовнішнім світом. У вашому прикладі, чи буде користувач коли-небудь викликати ваш читацький клас за допомогоюfind all the non-numerical fields in a line?

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

Потік TDD становить:

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

Це НЕ робити, "оскільки мені в майбутньому знадобиться X як приватний метод, дозвольте реалізувати його і спершу протестувати його". Якщо ви виявите, що ви робите це, ви робите «червоний» етап неправильно. Це, мабуть, тут є вашою проблемою.

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

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

9

У вас виникає поширена помилка з тестуванням взагалі.

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

  • написати тест на функцію F
  • здійснити F
  • написати тест на функцію G
  • реалізувати G, використовуючи виклик F
  • написати тест на функцію H
  • реалізувати H, використовуючи виклик до G

і так далі.

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

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

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


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

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

8

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

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

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

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


4

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

(Мені не зовсім зрозуміло, чим займається ваша функція. Чи повертає вона рядок із вмістом файлу з викресленими нечисловими значеннями?)

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

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


3

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

Є стара приказка.

Коли ви не плануєте, ви плануєте провалитись.

Люди, здається, думають, що коли ти TDD, ти просто сідаєш, пишеш тести, і дизайн просто магічним чином станеться. Це неправда. Потрібно мати план високого рівня. Я виявив, що найкращі результати отримую від TDD, коли спочатку розробляю інтерфейс (публічний API). Особисто я створюю фактичне, interfaceяке визначає клас насамперед.

ах, я написав якийсь "код", перш ніж писати будь-які тести! Ну, ні. Я цього не зробив. Я написав контракт, який слід дотримуватися, дизайн . Я підозрюю, що ви можете отримати подібні результати, записавши діаграму UML на графічному папері. Справа в тому, що у вас повинен бути план. TDD не є ліцензією на те, що мимоволі хакерує хакерство на фрагмент коду.

Я справді відчуваю, що "Тест по-перше" - це помилка. Дизайн По перше , то випробування.

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


2

Пам’ятайте, що тести також можуть бути відновлені! Якщо ви робите метод приватним, ви зменшуєте загальнодоступний API, а значить, цілком прийнятно викинути деякі відповідні тести на цю "втрачену функціональність" (знижена складність AKA).

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

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

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


1
Хоча інші відповіді вірні тим, що приватний метод не повинен був бути записаний у червоний цикл, люди роблять помилки. І коли ви пройшли шлях помилки досить далеко, це відповідне рішення.
slebetman

2

Бувають випадки, коли приватний метод може бути відкритим методом іншого класу.

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

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


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

0

Цікаво, чому у вашої мови є лише два рівні конфіденційності, повністю публічні та повністю приватні.

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

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


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

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

0

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


0

Я пережив це і відчув твій біль.

Моїм рішенням було:

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

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

Наприклад, у мене часто є:

  • тест низького рівня 1
  • код для його задоволення
  • тест низького рівня 2
  • код для його задоволення
  • тест низького рівня 3
  • код для його задоволення
  • тест низького рівня 4
  • код для його задоволення
  • тест низького рівня 5
  • код для його задоволення

то я маю

  • тест низького рівня 1
  • тест низького рівня 2
  • тест низького рівня 3
  • тест низького рівня 4
  • тест низького рівня 5

Однак якщо я зараз додаю функції вищого рівня, які називають це, які мають багато тестів, я можу зараз знизити ці тести низького рівня на просто:

  • тест низького рівня 1
  • тест низького рівня 5

Диявол знаходиться в деталях, і здатність це зробити буде залежати від обставин.


-2

Чи обертається сонце навколо Землі чи земля навколо сонця? На думку Ейнштейна, відповідь "так", або обидві, оскільки обидві моделі відрізняються лише точкою зору, так само інкапсуляція та тестова розробка лише суперечать тому, що ми думаємо, що вони є. Ми сидимо тут, як Галілей та Папа, кидаючи образи один на одного: дурень, хіба ти не бачиш, що приватні методи теж потребують тестування; єретик, не порушуйте інкапсуляцію! Так само, коли ми визнаємо, що правда грандіозніша, ніж ми думали, чи можемо ми спробувати щось подібне до інкапсуляції тестів для приватних інтерфейсів, щоб тести для публічних інтерфейсів не порушували інкапсуляцію.

Спробуйте це: додайте два способи, той, який не має вводу, але справедливо повертає кількість приватних тестів і той, який приймає тестовий номер як параметр і повертає пропуск / збій.


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