Должны ли частные / защищенные методы проходить модульное тестирование? - PullRequest
72 голосов
/ 09 апреля 2011

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

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

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

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

Мои мысли:

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

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

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

Ответы [ 12 ]

99 голосов
/ 09 апреля 2011

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

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

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

37 голосов
/ 08 июля 2014

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

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

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

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

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

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

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

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

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

34 голосов
/ 10 апреля 2011

Вы писали:

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

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

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

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

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

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

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

13 голосов
/ 09 апреля 2011

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

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

12 голосов
/ 09 апреля 2011

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

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

8 голосов
/ 05 января 2013

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

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

5 голосов
/ 18 августа 2015

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

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

Взятие на себя (1) Утверждение ожидаемого поведения:

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

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

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

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

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

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

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

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

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

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

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

Что с этим делать?

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

Да и нет.

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

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

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

4 голосов
/ 09 апреля 2011

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

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

2 голосов
/ 25 июля 2014

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

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

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

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

1 голос
/ 08 марта 2017

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...