Иногда закрытые функции модуля или класса - это просто пока не извлекаемые внутренние единицы функциональности, которые могут заслуживать собственных тестов. Так почему бы не проверить их? Мы будем писать тесты для них позже , если / когда они извлечены. Так почему бы не написать тесты сейчас, когда они все еще являются частью одного и того же файла?
Демонстрировать:
Сначала я написал 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
содержат большую часть функциональности модуля. Каждый из них может быть публичной функцией отдельного «внутреннего» модуля. Но они еще не развиты и не достаточно велики, чтобы их можно было извлечь в отдельные файлы.
Поэтому тестирование этих функций кажется правильным, поскольку они являются важными единицами функциональности. Если бы они были в разных модулях как публичные функции, мы бы их протестировали. Так почему бы не протестировать их, когда они еще (или никогда) не извлечены в другой файл?
Ответы:
Необходимость тестирования - это не то же самое, что необходимость быть публичной.
Нетривиальный код нуждается в тестировании независимо от подверженности. Не публичное поведение не должно существовать, не говоря уже о том, чтобы быть проверенным.
Эти противоречивые взгляды могут привести к тому, что вы захотите сделать каждую функцию общедоступной или отказаться выделять код в функцию, если она не будет публичной.
Это не ответ. Будьте готовы создавать частные вспомогательные функции. Протестируйте их через открытый интерфейс, который использует его как можно больше.
Если тестирование через открытый интерфейс не выполняет частную функцию в достаточной степени, частная функция пытается разрешить многое.
Валидация может помочь сузить возможности частной функции. Если вы не можете передать значение NULL через общедоступный интерфейс, вы все равно можете выдать исключение, если оно все равно получено.
Почему должен ты? Зачем проверять то, что вы никогда не увидите? Потому что все меняется. Это может быть приватным сейчас, но позже публичным. Код вызова может измениться. Код, который явно отклоняет null, делает понятным правильное использование и ожидаемое состояние.
Конечно, ноль может быть в порядке. Это просто пример здесь. Но если вы ожидаете чего-то, полезно прояснить это ожидание.
Это может быть не тот тип тестирования, который вы имели в виду, но, надеюсь, вы будете готовы создавать частные вспомогательные функции, когда это уместно.
Желание проверить это хорошо, но оно не должно быть движущей силой в дизайне вашего публичного API. Разработайте общедоступный API, чтобы быть простым в использовании. Скорее всего, не будет, если каждая функция является публичной. API должен быть чем-то, что люди могут понять, как использовать, не углубляясь в код. Не позволяйте таким людям задуматься, для чего нужна эта странная вспомогательная функция.
Сокрытие общедоступных вспомогательных функций во внутреннем модуле - это попытка уважать потребность в чистом API, одновременно предоставляя помощников для тестирования. Я не скажу, что это неправильно. Возможно, вы делаете первый шаг к другому архитектурному слою. Но, пожалуйста, овладейте искусством тестирования частных вспомогательных функций с помощью общедоступных функций, которые их используют в первую очередь. Таким образом, вы не будете чрезмерно использовать этот обходной путь.
источник
Краткий ответ: нет
Более длинный ответ: да, но через общедоступный «API» вашего класса
Вся идея закрытых членов класса заключается в том, что они представляют функциональность, которая должна быть невидимой вне «единицы» кода, какой бы большой вы ни хотели определить эту единицу. В объектно-ориентированном коде этот модуль часто оказывается классом.
Ваш класс должен быть спроектирован так, чтобы можно было задействовать все частные функции с помощью различных комбинаций состояния ввода. Если вы обнаружите, что нет относительно прямого способа сделать это, это, вероятно, намек на то, что ваш дизайн требует более пристального внимания.
После прояснения вопроса это просто вопрос семантики. Если рассматриваемый код может работать как отдельный автономный модуль и тестируется так, как если бы он был общедоступным кодом, я не вижу никакой выгоды в том, чтобы не переносить его в отдельный модуль. В настоящее время это только вводит в заблуждение будущих разработчиков (включая вас самих, через 6 месяцев), почему явно открытый код скрыт внутри другого модуля.
источник
Весь смысл частных функций в том, что они являются скрытыми деталями реализации, которые могут быть изменены по желанию, без изменения общедоступного API. Для вашего примера кода:
Если у вас есть серия тестов, которые используют только
public_func
, то если вы переписываете его в:тогда, пока результат возврата для определенного значения
a
остается неизменным, тогда все ваши тесты будут хорошими. Если возвращаемый результат изменяется, тест не пройден, что подчеркивает тот факт, что что-то сломалось.Это все хорошо: статический публичный API; хорошо инкапсулированные внутренние работы; и надежные тесты.
Однако, если бы вы написали тесты для
_do_stuff
или_do_more_stuff
затем внесли указанное выше изменение, у вас теперь будет куча неработающих тестов не потому, что функциональность изменилась, а потому, что реализация этой функциональности изменилась. Эти тесты должны были бы быть переписаны для работы с новыми функциями, но если бы они работали, все, что вы знаете, это то, что эти тесты работали с новыми функциями. Вы бы потеряли исходные тесты и поэтому не знали бы,public_func
изменилось ли поведение, и поэтому ваши тесты были бы в основном бесполезны.Это плохо: меняющийся API; открытые внутренние работы, тесно связанные с испытаниями; и хрупкие тесты, которые изменяются, как только вносятся изменения в реализацию.
Так что нет, не тестируйте частные функции. Когда-либо.
источник