unit tests
Технически - нет, не нужно. До всего можно добраться. В крайнем случае модифицируя байт-код агентом (см. PowerMock).
А вот практически приходится. У нас были тесты, проверявшие права доступа. И чтобы переинициализировать (очистить после теста) классы, которые тестами затрагивались, приходилось что-то около 10-15 статических полей то в null то в 0 то в false сбрасывать. И каждый раз, когда классы менялись (то просто поле переименуют, то его в другой класс перенесут, то вообще удалят), сыпались тесты => выкатывать изменения нельзя.
Договорились что в двух классах будут protected методы junitReset(), а наши тесты будут их вызывать. После этого, при таких же изменениях как и раньше, сразу вылетает ошибка компиляции в junitReset(), его правят и тесты работают как и раньше.
Теперь от этих полей избавились, осталось 2, но метод убирать не хотят. Говорят нам проще с ним, чем время от времени в ошибках тестов разбираться.
Не, меня его синтакс пугает. Ну и делать моки конструкторов, статических и приватных методов должно быть больно :)
А jmockit слишком упрощает. Про то что ты его запускаешь с агентом упоминается, но не поясняют а что же это такое. А это, товарищи - модификация всего загружаемого байт кода. И что ты в результате тестишь не знают даже разработчики jmockit-а.
Не учите папу кашлять. Не надо мне про синглтоны рассказывать, я сам кому хочешь расскажу.
Я же писал, что если есть 10-летний лигаси-код в огромном энтерпрайз-продукте, который напичкан синглтонами под завязку, то никто в здравом уме не пойдёт всё это "рефакторить". За редким исключением, когда менеджмент понимающий и архитектор грозится уволиться, см выше.
А мои каракули в том посте - это был вопрос, как вот такие конструкции можно заменить моками. Вопрос оказался в пустоту, потому что товарищ на другой платформе работает. А в джабе я не силён, чтобы пример на джабе слабать.
Замена модификатора сеттера на internal никаким образом не поможет синглтон сделать mockable.
ЗЫ. Хот-патчинг - это замена кода приложения в процессе выполнения приложения. Есть на всех платформах, в том числе .NET. Например, можно любые методы менять на что угодно и вообще творить всякое непотребство. К сожалению, приходилось применять: ручная генерация IL и потом хардкорный asm, чтобы заставить jitter всё это дело схавать и не подавиться.
Идея в том, что по S (single responsibility) каждый класс, метод, функция должны выполнять только одну задачу. Это позволяет минимизировать изменения в программе, если изменились требования к этой задаче. Любое изменение - это потенциально источник ошибок. Меньше изменений - меньше ошибок.
В примере функция и лезет в веб, и получает контент, и парсит XML. По SOLID, функция, которая парсит XML, должна на вход его получать. Откуда он пришёл, ей должно быть по барабану. Другая функция лезет в веб и качает данные. Точка. Ей по барабану, кто эти данные использовать будет и как. И так далее.
Разбивая логику на связанные, но независимые блоки, автоматом получаем тестируемые блоки, поскольку их зависимости минимальны и есть чёткое понимание, чего давать на вход и чего ждать на выходе.
что касается идей о задачах, выполняемых ф-ми, но приведенная мной одну только и решает. и одновременно - несколько, как и любая другая практически.
ф-я в примере не "лезет в вэб". туда лезет метод get модула requests. достанет он мне что-то из интернета снаружи от ф-ии, и я это передам аргументом, будет только лишний аргумент в заголовке ф-ии и непонятно в контексте вызывающем, зачем мы лезем куда-то в интернет, когда нам абсолютно безразлично, как ф-я будет добывать эти suggestions: у нас своя логика, построенная ни том, получили мы их или нет. а она пусть хоть из пальца, хоть из файла, хоть генерирует случайно, ...
в общем, у этой ф-ии задача - сформировать и выдать список подсказок, и ее решением она и занимается.
вообще, здравому смыслу есть место где-нибудь во всех этих S, unit test, TDD и прочих религиях?
ps. кроме того, если "лезть в интернет" снаружи ф-ии, то представим себе, что ту, наружную, вызывающую, мы тоже должны оюниттестить... т.е. проблему просто перенесли этажом выше.
не проблема за пэтчить это "лазание в вэб", и пусть мок возвращает нам "правильный контент", который мы можем где-то прочесть из файла (ведь не будем же мы тащить в тест-код контент длиной несколько метров текста?), но что мы таким образом протестировали? то, что и без теста очевидно? я остаюсь при мысли, что не на каждый пук следует писать юнит-тест. приведенный пример попадает в категорию тестируемых, но смысла в такам юниттестировании - ноль, одни затраты.
Не надо мне про синглтоны рассказывать, я сам кому хочешь расскажу.
Я не знаю, что ты можешь рассказать про синглтоны, но привести рабочий код синглтона ты не смог.
Замена модификатора сеттера на internal никаким образом не поможет синглтон сделать mockable.
Ошибаешься. Почитай про InternalsVisibleToAttribute. В отличае от тебя, я не только видел синглтоны в легаси коде, но и инжектил в эти синглтоны свои мок-объекты.
ЗЫ. Хот-патчинг - это замена кода приложения в процессе выполнения приложения.
Ну совершенно очевидно, что это тоже не нужно, т.к. на крайний случай можно воспользоваться рефлекшенами и сделать инжект.
что касается идей о задачах, выполняемых ф-ми, но приведенная мной одну только и решает. и одновременно - несколько, как и любая другая практически.
В полемику сейчас вступать нет много времени, но с подобной точкой зрения мне трудно согласится, хотя можно понять ход Ваших мыслей.
Если рассматривать функцию как черный ящик, то она выдает то что вам требуется. Но функция имеет еще и "чёрный ход" она запрашивает откуда-то данные и их еще и перерабатывает.
Иначе говоря функция не "сквозная" она не занимается переработкой данных, что нарушает принцип тестирования: мы задаем данные с известным результатом и сравниваем полученный результат с ожидаемым.
Так что минимальные изменения, которые требуются - это дать функции "вход". Закиньте ей просто интерфейс для забора данных.
я не вижу принципиальной разницы, как ф-я получит данные (в силу незнания азов, видимо : ). можно просто запэтчить в тесте вход, не заморачиваясь с интерфейсами. иначе вы добавляете сложности и вообще "лишних забот" вызывающей ф-ии (возможно, не одной, а десятку), которые не входят в их S. и если когда-нибдуь ф-я get_suggestions() будет решать свою задачу иначе, не "лазя в вэб", то вам придется переписывать все вызывающие куски, и все их тесты.
я остаюсь при мнении, что юнит тесты на подобные ф-ии - религиозный ритуал. если кому-то необходимо (кошерно по его вере) - то свобода совести ему открывает для этого дорогу. но мне она же оставляет выбор не делать никаких юниттестов там, где это неуместно.
кстати, таки сделал через @mock.patch(...), чудесно рабатыват,
но польза - единственная: познакомился, как оно устроено. тест в дальнейшем использовать для тестирования этой ф-ии не буду, т.к. бессмысленно. только как пример, откуда можно будет списать, когда это посчитаю разумным, т.е. юнит тест будет облегчать жизнь, а не усложнять и без того непростое
Нужно почитать про SOLID - это альфа и омега современного ООП
c SOLID нужно тоже аккуратно. Некоторые с ним не согласны: egor256: SOLID Is OOP for Dummies
Нда-с. "Дураков у нас на сто лет вперёд припасено." (c) Егорка чушь прогнал. Причём он кроме Open-Close и не спорит ни с чем. И аргументов никаких не приводит кроме "а чо, это надо?". А к остальному у него претензия "а раньше оно по другому звалось." Не читайте его больше.
Кстати, что-то мне кажется что похожую статью мы тут года два назад обсуждали...
P.S. Нашёл. Полтора года назад именно про эту статью то же самое писал :). https://foren.germany.ru/arch/showmessage.pl?Number=323101...