Іноді приватні функції просто ще мають бути вилучені внутрішні одиниці функціональності. То чому б не перевірити їх?


9

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

Демонструвати:

введіть тут опис зображення

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


Припустимо, у мене є модуль із такими функціями (це також міг бути клас):

def public_func(a):
    b = _do_stuff(a)
    return _do_more_stuff(b)

_do_stuffі _do_more_stuffє "приватними" функціями модуля.

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

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

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



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

3
"Чи варто перевірити приватні функції?" Ні. Ніколи, ніколи, ніколи.
Девід Арно

2
@DavidArno Чому? Яка альтернатива тестуванню внутрішніх справ? Тільки інтеграційні тести? Або оприлюднення більше речей? (хоча в моєму досвіді я в основному
тестую

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

Відповіді:


14

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

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

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

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

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

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

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

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

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

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

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


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

Я скажу, що прошу те саме, що й інші хлопці, які тут відповіли :) Я хотів би почути думку всіх.
Авів Кон

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

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

7

Коротка відповідь: Ні

Більш відповідь: Так, але через загальнодоступний "API" вашого класу

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

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


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


Привіт, дякую за вашу відповідь :) Будь ласка, перечитайте питання, яке я відредагував, щоб уточнити.
Авів Кон

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

Я скажу, що прошу те саме, що й інші хлопці, які тут відповіли :) Я хотів би почути думку всіх.
Авів Кон

5

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

def public_func(a):
    b = _do_stuff(a)
    return _do_more_stuff(b)

Якщо у вас є ряд тестів, які використовуються лише public_funcтоді, ви можете переписати їх на:

def public_func(a):
    b = _do_all_the_new_stuff(a)
    return _do_all_the_old_stuff(b)

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

Це все добре: статичний публічний API; добре укладені внутрішні вироби; і надійні випробування.

Однак, якщо ви писали тести для _do_stuffабо _do_more_stuffпотім вносили вищезгадані зміни, у вас зараз з'явиться купа зламаних тестів не тому, що змінилась функціональність, а тому, що реалізація цієї функціональності змінилася. Ці тести потребували б переписування для роботи з новими функціями, але, змусивши їх працювати, все, що ви знаєте, - це те, що вони працювали з новими функціями. Ви втратили б оригінальні тести, і тому не знали б, чи public_funcзмінилася поведінка, і тому ви тести були б марними.

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

Тому ні, не перевіряйте приватні функції. Колись.


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

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

Що ви насправді сперечаєтесь, це те, що у вас не повинно бути приватних функцій.
Роберт Харві

1
@AvivCohn Вони або достатньо великі, щоб зробити тестування, і в цьому випадку вони досить великі, щоб отримати власний файл; або вони досить малі, що вам не потрібно тестувати їх окремо. Так що це?
Довал

3
@RobertHarvey Ні, це робить аргумент "розбийте великі класи на нещільно зв'язані компоненти, якщо це необхідно". Якщо вони насправді не є загальнодоступними, це, мабуть, хороший випадок використання для приватної видимості пакетів.
Доваль
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.