Питання Як протестувати приватну функцію або клас, що має приватні методи, поля або внутрішні класи?


Як провести тестування (за допомогою xUnit) класу, який має внутрішні приватні методи, поля або вкладені класи? Або функція, яка є приватною за наявності внутрішня зв'язок (static в C / C ++) або в приватному (анонімний) простір імен?

Мені здається погано змінити модифікатор доступу для методу або функції, щоб мати змогу запустити тест.


2268


походження


Найкращий спосіб перевірити приватний метод не тестувати його безпосередньо - Surya
Перевірте статтю Тестування приватних методів за допомогою JUnit та SuiteRunner. - Mouna Cheikhna
Я не погоджуюсь. Метод (публічний), який довгий або складний для розуміння, повинен бути рефакторингований. Було б нерозумно не тестувати малі (приватні) методи, які ви отримуєте, а не лише загальнодоступні. - Michael Piefel
Не тестування будь-яких методів просто тому, що видимість є дурною. Навіть тест на одиницю повинен містити приблизно найменший шматочок коду, і якщо ви перевіряєте лише загальнодоступні методи, ви ніколи не будете точно впевнені, де виникає помилка - цей метод чи якийсь інший. - Dainius
Вам потрібно протестувати клас функціональність, а не його реалізація. Хочете перевірити приватні методи? Перевірте загальнодоступні методи, які їх викликають. Якщо функціональність, запропонований класом, перевіряється ретельно, його внутрішні елементи продемонстрували правильність і надійність; вам не потрібно перевіряти внутрішні умови. Тести повинні підтримувати відокремлення від випробуваних класів. - Calimar41


Відповіді:


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

Внутрішньо ми використовуємо помічники, щоб отримати / встановити private і private static змінні, а також викликати private і private static методи Наступні шаблони дозволять вам робити майже все, що стосується приватних методів і полів. Звичайно, ви не можете змінити private static final змінні через відображення.

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

І для полів:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Примітки:
  1 targetClass.getDeclaredMethod(methodName, argClasses) дозволяє розглянути private методи Те саме стосується і    getDeclaredField.
  2. The setAccessible(true) Потрібно розігрувати з привалами.


1417



Корисно, якщо ви не знаєте API, можливо, але якщо вам потрібно перевірити приватні методи таким чином, то є щось з вашим дизайном. Оскільки інший плакат говорить про те, що підроздільне тестування повинно перевіряти контракт класу: якщо контракт є занадто широким та створює надмірну кількість системи, тоді дизайн має бути вирішено. - andygavin
Дуже корисний. Використовуючи це, важливо мати на увазі, що це буде невдало, якщо тести будуть виконуватися після обфусування. - Rick Minerich
Прикладний код не працював для мене, але це зробило все більш чітке: java2s.com/Tutorial/Java/0125__Reflection/... - Rob
Набагато краще, ніж безпосередньо використовувати відображення, було би використовувати для нього таку бібліотеку, як Powermock. - Michael Piefel
Ось чому тестовий дизайн є корисним. Це допомагає з'ясувати, що потрібно виставити, щоб перевірити поведінку. - Thorbjørn Ravn Andersen


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

  1. Приватним методом є мертвий код
  2. Існує дизайнерський запах біля класу, який ви випробовуєте
  3. Метод, який ви намагаєтеся перевірити, не повинен бути приватним

507



Не згоден Це абсолютно справедливо для того, щоб мати алгоритм у приватному методі, який потребує додаткового тестування об'єкта, ніж це практично через загальнодоступні інтерфейси класу. - Mr. Shiny and New 安宇
Гей мій Блискучий Так, але тоді у вас будуть крихкі випробування. Також див. Номер 2 у моїй відповіді. - Trumpi
Тяжкий тест - це тест, який дуже швидко збігається, коли відбувається зміна коду. Як правило, це трапляється, коли результат тесту грунтується на тому, що робить метод, а не на очікуваних виходах та побічних ефектах, якщо заданий набір введених даних. В ідеалі зміна коду, яка не змінює результати, не повинна порушувати тест. - aro_biz
@Містер. Блискучі та нові: Якщо ваш приватний метод досить складний, щоб гарантувати незалежне тестування, то досить складно мати свій клас. Клас може бути звичайно внутрішнім (тобто не доступний з інших пакетів). - sleske
@sleske, я не згоден. Ви можете мати невеликий приватний метод, який за дизайном вам потрібно було бути приватним. і я б краще тестувати кожен невеликий фрагмент коду, ніж протестувати цей приватний метод через публічний. Цей спосіб тестування буде спрямований на компонентний тест. - despot


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

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

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

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


272



Питання полягало в тому, як перевірити приватні методи. Ви кажете, що ви зробите для цього новий клас (і додайте значно більше складності) і запропонуйте не створювати новий клас. Отже, як випробувати приватні методи? - Dainius
Я думаю, що якщо у вас є метод, то не потрібно створювати інший клас, щоб просто перевірити цей метод. Я не думаю, що дизайн класу був тут питанням. Отже, я припускаю, що автор зробив все, щоб мати правильний дизайн раніше, таким чином, ввівши ще один клас для одного методу, який ви просто збільшили складність. Звичайно, коли у вас є достатньо складної програми, не буде очевидних помилок .. - Dainius
@Dainius: Я не пропоную створити новий клас виключно тому ви можете протестувати цей метод. Я думаю, що написання тестів може допомогти вам покращити свій дизайн: хороші конструкції легко перевірити. - Jay Bazuzi
Але ви погоджуєтесь, що хороший OOD може піддавати (оприлюднити) лише методи, необхідні для того, щоб цей клас / об'єкт правильно працював? всі інші повинні бути приватними / protectec. Отже, в деяких приватних методах існує певна логіка, а тестування ІМО цих методів лише покращить якість програмного забезпечення. Звичайно, я згоден з тим, що якщо який-небудь фрагмент коду складний, його слід розділити на окремі методи / клас. - Dainius
@ Даніус: додавання нового класу в більшості випадків зменшує складність. Просто вимірюйте це. Тестування в деяких випадках бореться з OOD. Сучасний підхід - перевага тестування. - AlexWien


Я використовував рефлексія робити це для Java у минулому, і на мій погляд це була велика помилка.

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

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


229



+1 до цього На мій погляд це найкраща відповідь на питання. Перевіряючи приватні методи, ви тестуєте реалізацію. Це поєднує мету одиничного тестування, тобто тестування входів / виходів контракту класу. Тест повинен тільки Знати досить про реалізацію, щоб висміювати методи, які він запускає за своїми залежностями. Більше нічого. Якщо ви не можете змінити свою реалізацію, не змінюючи тест - це шанси, що ваша тестова стратегія є поганою. - Colin M
@ Колін М Це насправді не те, що він просить хоча;) Нехай він вирішить це, ви не знаєте проект. - Aaron Marcus
Неправда. Це може зайняти багато зусиль, щоб випробувати невелику частину приватного методу через публічний метод, що використовує його. Загальнодоступний спосіб може вимагати значного налаштування, перш ніж досягти лінії, яка викликає ваш приватний метод - ACV


З цієї статті: Тестування приватних методів за допомогою JUnit та SuiteRunner (Білл Веннерс), у вас в основному є 4 варіанти:

  • Не перевіряйте приватні методи.
  • Дайте доступ до методів пакета.
  • Використовуйте вкладене тестування.
  • Використовуйте відображення.

187



@ user86614 Введення коду тесту в код продукту - не найкраща ідея. - Jimmy T.
@JimmyT., Залежить від кого "виробничий код" для. Я б назвав код, створений для програм, розміщених у VPN, цільовими користувачами яких є системні адміністратори, - це код виробництва. - Pacerier
@ Пазерер Що ти маєш на увазі? - Jimmy T.
5-й варіант, як зазначено вище, тестування відкритого методу, який викликає приватний метод? Правильно? - user2441441
@LorenzoLerate Я боровся з цим, тому що я займаюся вбудованим розвитком, і я хотів би, щоб моє програмне забезпечення було настільки маленьким, наскільки це можливо. Обмеження розміру та продуктивність є єдиною причиною, якою я можу думати.


Загалом одиничний тест призначений для здійснення загальнодоступного інтерфейсу класу чи підрозділу. Тому приватні методи - деталізація реалізації, яку ви не очікуєте перевірити явно.


96



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


Лише два приклади того, де я хочу перевірити приватний метод:

  1. Процедури розшифрування - Я б не Хочеш зробити їх видимими для когось, щоб побачити саме це заради тестування, ще кожен може використовувати їх для розшифрування. Але вони є внутрішній код, складний, і потрібно завжди працювати (очевидним винятком є ​​відображення, яке може використовуватися для перегляду навіть приватних методів у більшості випадків, коли SecurityManager не налаштовано, щоб запобігти цьому).
  2. Створення SDK для спільноти споживання Тут громадськість бере на себе зовсім інше значення, оскільки це це код, який може бачити весь світ (а не тільки в моєму додатку). я кладу код у приватні методи, якщо ні хочу, щоб користувачі SDK побачили це - I не бачиш це як запах коду, просто як працює SDK програмування. Але про Звичайно, я все ще повинен протестувати мій приватні методи, і вони там фактично функціональність мого SDK живе

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

Отже, мій компроміс включає в себе складне відображення JUnits, а не компрометує мою безпеку та SDK.


56



Хоча ви ніколи не повинні публікувати метод, щоб протестувати його, private це не єдина альтернатива. Немає модифікатора доступу package private і це означає, що ви можете перевірити це пристрій, якщо випробування вашого блоку живе в одному пакеті. - ngreen
@ngreen це все правда, але це не питання. ОП запитує про тестування приватних методів. За умовчанням не такий самий, як приватний; як зазначено, ви можете легко побачити метод доступу за замовчуванням із класу, просто задавши цей клас у тім же пакеті. За допомогою приватного доступу ви потребуєте відображення, що є цілим іншим набором ігор. - Richard Le Mesurier
Я коментував вашу відповідь, зокрема пункт 1, а не ОП. Не потрібно робити метод приватним лише тому, що ви не хочете, щоб він був відкритим. - ngreen
@ngreen true thx - я лінувався словом "громадськість". Я оновив відповідь, щоб включити загальнодоступний, захищений, за замовчуванням (і згадати про відображення). Справа, яку я намагався зробити, полягає в тому, що існує вагома причина того, що якийсь код буде секретним, однак це не повинно забороняти нам тестувати його. - Richard Le Mesurier
Дякую за те, що надали реальні приклади для всіх. Більшість відповідей є хорошими, але з теоретичної точки зору. У реальному світі нам потрібно приховати реалізацію від контракту, і ми все ще повинні протестувати це. Читаючи все це, я думаю, що, можливо, це має бути абсолютно новий рівень тестування з іншим іменем - Z. Khullah


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


53



Істинний факт. Проблема в тому, коли реалізація складніша, наприклад, якщо один загальнодоступний метод викликає кілька приватних методів. Який з них не вдалося? Або якщо це складний приватний метод, його не можна виставити та не переносити на новий клас - Z. Khullah
Ви вже згадали, чому приватний метод повинен бути протестований. Ви сказали "тоді це може бути", так що ви не впевнені. ІМО, чи повинен тестувати метод, є ортогональним до рівня доступу. - Wei Qiu