Должны ли частные/защищенные методы находиться под unit test?

В разработке TDD первое, что вы обычно делаете, это создать свой интерфейс, а затем начать писать модульные тесты против этого интерфейса. По мере прохождения процесса TDD вы должны создать класс, который реализует интерфейс, а затем в какой-то момент ваш unit test будет проходить.

Теперь мой вопрос касается частных и защищенных методов, которые мне, возможно, придется писать в моем классе в поддержку методов/свойств, открытых интерфейсом:

  • Если частные методы в классе имеют свои собственные модульные тесты?

  • Если защищенные методы в классе имеют свои собственные модульные тесты?

Мои мысли:

  • Тем более, что я кодирую интерфейсы, я не должен беспокоиться о защищенных/приватных методах, поскольку они являются черными ящиками.

  • Поскольку я использую интерфейсы, я пишу модульные тесты для проверки того, что определенный контракт определен надлежащим образом различными классами, реализующими интерфейс, поэтому снова я не должен беспокоиться о частных/защищенных методах, и они должны быть реализованы через модульные тесты, которые вызывают методы/свойства, определенные интерфейсом.

  • Если мое покрытие кода не показывает, что защищенные/частные методы попадают, тогда у меня нет правильных модульных тестов или у меня есть код, который не используется и должен быть удален.

Ответ 1

Нет, я не думаю об испытании частных или защищенных методов. Частные и защищенные методы класса не являются частью открытого интерфейса, поэтому они не подвергают общественному поведению. Как правило, эти методы создаются с помощью рефакторинга, который вы применяете после того, как ваш тест стал зеленым.

Таким образом, эти частные методы проверяются неявно тестами, которые утверждают поведение вашего открытого интерфейса.

В более философской заметке помните, что вы тестируете поведение, а не методы. Поэтому, если вы думаете о множестве вещей, которые может испытать испытуемый класс, если вы можете проверить и утверждать, что класс ведет себя так, как ожидалось, существуют ли частные (и защищенные) методы, которые используются внутри класса для реализации это поведение не имеет значения. Этими методами являются детали реализации общественного поведения.

Ответ 2

Я не согласен с большинством плакатов.

Самое важное правило: РАБОЧИЙ КОД ТРЕТЬЯ ТЕОРЕТИЧЕСКИЕ ПРАВИЛА о публичных/защищенных/приватных.

Ваш код должен быть тщательно протестирован. Если вы можете попасть туда, написав тесты для общедоступных методов, которые в достаточной мере реализуют защищенные/частные методы, это замечательно.

Если вы не можете, то либо рефакторинг, чтобы вы могли, либо сгибали защищенные/частные правила.

Там отличная история о психологе, который дал детям тест. Он дал каждому ребенку две деревянные доски с веревкой, прикрепленной к каждому концу, и попросил их пересечь комнату без прикосновения их ног к полу, как можно быстрее. Все дети использовали доски, как маленькие лыжи, одну ногу на каждой доске, держа их за веревки и скользив по полу. Затем он дал им ту же задачу, но использовал только одну плату. Они поворачивались/ "шли" по полу, одна нога на каждом конце одной доски - и они были БЫСТРО!

Просто потому, что Java (или любой другой язык) имеет функцию (private/protected/public), не обязательно означает, что вы пишете лучший код, потому что используете его!

Теперь всегда будут способы оптимизации/минимизации этого конфликта. На большинстве языков вы можете сделать метод защищенным (а не общедоступным) и поместить тестовый класс в тот же пакет (или что-то еще), и этот метод будет доступен для тестирования. Есть аннотации, которые могут помочь, как описано другими плакатами. Вы можете использовать отражение, чтобы получить частные методы (yuck).

Контекст также имеет значение. Если вы пишете API для использования внешними людьми, более важным является public/private. Если это внутренний проект - кто действительно заботится?

Но в конце дня подумайте о том, сколько ошибок было вызвано отсутствием тестирования. Затем сравните с количеством ошибок, вызванных "чрезмерно видимыми" методами. Этот ответ должен принять ваше решение.

Ответ 3

Вы писали:

В разработке TDD, первая вещь вы обычно делаете, это создавать свои интерфейс, а затем начните писать модульные тесты против этого интерфейса. В виде вы прорабатываете процесс TDD вы должны создать класс, который реализует интерфейс, а затем в какой-то момент ваш unit test пройдет.

Пожалуйста, позвольте мне перефразировать это в BDD:

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

* Может быть фактическим Interface или просто доступным API класса, например: Ruby не имеет интерфейсов.

Вот почему вы не проверяете частные методы - потому что тест является примером того, как использовать класс, и вы фактически не можете их использовать. Что-то, что вы можете сделать, если хотите, делегировать обязанности в приватных методах сотрудничающему классу, а затем mock/заглушить этого помощника.

С защищенными методами вы говорите, что класс, который расширяет ваш класс, должен иметь определенное поведение и предоставлять некоторую ценность. Затем вы можете использовать расширения своего класса, чтобы продемонстрировать это поведение. Например, если вы пишете упорядоченный класс коллекции, вы можете продемонстрировать, что два расширения с тем же содержимым демонстрировали равенство.

Надеюсь, это поможет!

Ответ 4

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

Защищенные методы образуют другой контракт между вашим классом и его будущими детьми, поэтому вы должны действительно тестировать его в такой же степени, как и ваш публичный интерфейс, чтобы гарантировать, что контракт хорошо определен и реализован.

Ответ 5

Нет! Только тестовые интерфейсы.

Одним из больших преимуществ TDD является обеспечение того, что интерфейс работает независимо от того, как вы выбрали реализацию частных методов.

Ответ 6

Завершив сказанное выше, я бы сказал, что защищенные методы являются частью какого-либо интерфейса: это просто случай, когда он наследуется, а не композиция, о чем все склонны думать при рассмотрении интерфейсов.

Маркировка метода как защищенного, а не частного означает, что он будет использоваться сторонним кодом, поэтому необходимо определить и протестировать какой-то контракт, как это происходит с обычными интерфейсами, определенными публичными методами, которые открыты как для наследование и состав.

Ответ 7

Есть две причины для написания тестов:

  • Утверждение ожидаемого поведения
  • Предотвращение регрессии поведения

Принять (1) Утверждение ожидаемого поведения:

Когда вы утверждаете ожидаемое поведение, вы хотите убедиться, что код работает так, как вы думаете. Это эффективно автоматизированная процедура рутинной проверки вручную, которую любой разработчик выполнил бы при реализации любого кода:

  • Делал ли что-то, что я только пишу, работает?
  • Закончен ли этот цикл?
  • Это цикл в том порядке, в котором я думаю?
  • Будет ли это работать для нулевого ввода?

Это вопросы, которые мы все отвечаем в наших головах, и, как правило, мы также пытаемся выполнить код в наших головах, убедитесь, что он выглядит так, как будто он работает. Для этих случаев часто бывает полезно, чтобы компьютер отвечал на них окончательно. Поэтому мы пишем unit test, которые утверждают, что он делает. Это дает нам уверенность в нашем коде, помогает нам быстро находить дефекты и даже может реально реализовать код.

Это хорошая идея сделать это, где бы вы ни находились. Любой код, который немного сложно понять, или нетривиальным. Это может выиграть даже тривиальный код. Это все о вашей собственной уверенности. Как часто это делать и как далеко идти будет зависеть от вашего собственного удовлетворения. Остановитесь, если вы можете с уверенностью ответить Да: вы уверены, что это работает?

Для такого тестирования вы не заботитесь о видимости, интерфейсах или любом из них, вам остается только иметь рабочий код. Так что да, вы проверили бы частные и защищенные методы, если бы почувствовали, что им нужно пройти тестирование, чтобы вы ответили "Да" на вопрос.

Принятие (2) Предотвращение регрессии поведения:

После того, как у вас есть рабочий код, у вас должен быть механизм для защиты этого кода от будущего ущерба. Если бы никто никогда не касался вашего источника и вашего конфига никогда, вам это не понадобится, но в большинстве случаев вы или другие пользователи будут касаться источника и конфигураций вашего программного обеспечения. Это внутреннее проворство, скорее всего, нарушит ваш рабочий код.

Механизмы существуют на большинстве языков уже как способ защиты от этого ущерба. Функции видимости - это один механизм. Частный метод изолирован и скрыт. Инкапсуляция - еще один механизм, где вы разделяете вещи, так что изменение других отсеков не влияет на других.

Общий механизм для этого называется: кодирование на границу. Создавая границы между частями кода, вы защищаете все внутри границы от вещей, находящихся за ее пределами. Границы становятся точкой взаимодействия, и договор, с которым взаимодействуют вещи.

Это означает, что изменения границы, либо нарушая ее интерфейс, либо нарушая ожидаемое поведение, могут повредить и, возможно, нарушить другие границы, на которые он опирается. Вот почему хорошая идея иметь unit test, который нацелен на эти границы и утверждает, что они не изменяются в семантике и в поведении.

Это ваш типичный unit test, о котором говорят все, когда упоминают TDD или BDD. Дело в том, чтобы затвердеть границы и защитить их от перемен. Вы не хотите проверять частные методы для этого, потому что частный метод не является границей. Защищенные методы - это ограниченная граница, и я буду защищать их. Они не подвергаются воздействию мира, но все еще подвергаются воздействию других отсеков или "единиц".

Что можно сделать из этого?

Как мы видели, есть веская причина для unit test общедоступных и защищенных методов, поскольку утверждать, что наши интерфейсы не меняются. И есть также веские причины для проверки частных методов, чтобы утверждать наши работы по внедрению. Итак, должны ли мы unit test их всех?

Да и Нет.

Во-первых. Протестируйте все методы, которые, по вашему мнению, вам нужны для окончательного доказательства того, что он работает в большинстве случаев, чтобы быть уверенным в том, что ваш код работает независимо от видимости. Затем отключите эти тесты. Они проделали там работу.

Наконец: Напишите тесты для своих границ. Имейте unit test для каждой точки, которая будет использоваться другими единицами вашей системы. Убедитесь, что этот тест подтверждает семантический контракт, имя метода, количество аргументов и т.д. Также убедитесь, что тест подтверждает доступное поведение устройства. Ваш тест должен продемонстрировать, как использовать устройство, и что может сделать устройство. Держите эти тесты включенными, чтобы они запускались при каждом нажатии на код.

ПРИМЕЧАНИЕ. Причина, по которой вы отключили первый набор тестов, - это разрешить работу рефакторинга. Активный тест - это кодовая связь. Это предотвращает будущую модификацию тестируемого кода. Вы только этого хотите для своих интерфейсов и контрактов на взаимодействие.

Ответ 8

Нет, вы не должны тестировать частные методы (как бы вы никоим образом не использовали что-то ужасное, как отражение). С защищенными методами это немного менее очевидно в С#, вы можете сделать вещи защищенными внутренними, и я думаю, что это нормально, чтобы протестировать производные классы, которые реализуют всю свою функциональность с помощью шаблонов шаблонов.

Но, в общем, если вы считаете, что ваши общедоступные методы слишком много делают, тогда пришло время реорганизовать ваши классы на более атомные классы, а затем проверить эти классы.

Ответ 9

Я тоже согласен с ответом @kwbeam о том, чтобы не тестировать частные методы. Однако важный момент, который я хотел бы выделить: защищенные методы являются частью экспортируемого API класса и, следовательно, ДОЛЖНЫ быть протестированы.

Защищенные методы могут не быть общедоступными, но вы определенно предоставляете возможность использования/переопределения подклассов. Что-то вне класса может получить к ним доступ, и, следовательно, вам необходимо обеспечить, чтобы эти защищенные члены вели себя в ожидании. Поэтому не проверяйте частные методы, но проверяйте общедоступные и защищенные методы.

Если вы считаете, что у вас есть частный метод, который содержит критическую логику, я бы попытался извлечь его в отдельный объект, изолировать его и предоставить способ проверить его поведение.

Надеюсь, что это поможет!

Ответ 10

Если вы нацелены на высокий охват кода (я предлагаю вам это делать), вы должны протестировать все ваши методы, независимо от того, являются ли они частными или защищены.

Защищенный - это своего рода разная точка обсуждения, но, судя по всему, его вообще не должно быть. Либо он разбивает инкапсуляцию на развернутый код, либо заставляет вас наследовать от этого класса, просто до unit test, даже иногда вам не нужно наследовать.

Простое скрытие метода для клиента (создание частного) не дает ему привилегии не проверяться. Поэтому они могут быть проверены публичными методами, как упоминалось ранее.

Ответ 11

Я согласен со всеми: ответ на ваш вопрос "нет".

Действительно, вы совершенно правы в своем подходе и своих мыслях, особенно в отношении охвата кода.

Я бы также добавил, что вопрос (и ответ "нет" ) также применим к общедоступным методам, которые вы можете ввести в классы.

  • Если вы добавляете методы (общедоступные/защищенные или закрытые), потому что они делают неудачный тестовый проход, то вы более или менее достигли цели TDD.
  • Если вы добавляете методы (public/protected или private), потому что вы просто решаете, нарушая TDD, тогда ваш охват кода должен их поймать, и вы сможете улучшить свой процесс.

Кроме того, для С++ (и я должен думать только для С++) я реализую интерфейсы, используя только частные методы, чтобы указать, что класс должен использоваться только через интерфейс, который он реализует. Это мешает мне ошибочно называть новые методы, добавленные в мою реализацию из моих тестов.

Ответ 12

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

Я думаю, что как только у нас будет идентифицируемая единица, выиграет от модульных тестов, независимо от того, будет ли он открыт через открытый API или нет.

Ответ 13

уна ла дас роурамента эс басура лента сэмпер ладас роурамента уна правая пудента.