Comments 12
>И приходилось выбирать: или красивый дизайн, или качественное покрытие тестами
Я думаю вам стоит выкинуть PowerMock и почитать про dependency injection… Моки на статик методы это зло
Я думаю вам стоит выкинуть PowerMock и почитать про dependency injection… Моки на статик методы это зло
+6
А при чем тут dependency injection (который я, к слову, неплохо знаю) и статик методы? Существует множество сторонних библиотек с набором utility-классов со статическими функциями. Зачастую, в таких ситуациях можно обойтись и без использования моков. А иногда их очень не хватает. Здесь я не призывал использовать статики или делать моки на все подряд. Ко всему же надо подходить с головой.
+1
Подход «с головой» к пробелеме написания стабов для статик методов заключается в замене static method на instance method и DI.
Можете привести пример где вам надо сделать mock на utility-классы со статическими функциями?
Можете привести пример где вам надо сделать mock на utility-классы со статическими функциями?
+1
Научите заменять static метод в сторонней библиотеке? Пример… ByteBuffer.allocate()
0
Можете привести пример где вам надо сделать mock на utility-классы со статическими функциями?
То есть не пример статической функции, это я и сам найду.
А пример где для тестирование надо сделать мок статической функции
0
Пример придуманный и совершенно сферический:
Опять же, всегда можно придраться, почему ByteBuffer не приходит извне функции. Но еще раз напоминаю, что это лишь пример, такой же сферический, как те, которые приведены в статье. Однако, похожие ситуации в жизни не раз бывали и в них не к чему было придраться. Просто на вскидку сложно вспомнить что то конкретное.
Да, в этом примере очень бы хотелось проверить, выполняется ли flip() для буфера. Предположим, что если его кто то удалит, все будет плохо.
public ByteBuffer serialize(Object obj) {
ByteBuffer buffer = ByteBuffer.allocate(new byte[100]);
serializer.serialize(object, buffer);
buffer.flip();
return buffer;
}
Опять же, всегда можно придраться, почему ByteBuffer не приходит извне функции. Но еще раз напоминаю, что это лишь пример, такой же сферический, как те, которые приведены в статье. Однако, похожие ситуации в жизни не раз бывали и в них не к чему было придраться. Просто на вскидку сложно вспомнить что то конкретное.
Да, в этом примере очень бы хотелось проверить, выполняется ли flip() для буфера. Предположим, что если его кто то удалит, все будет плохо.
+1
Эмм, пример и правда слишком сферический, тут нечего даже сказать.
Скорее всего тут не надо проверять что «вызван метод flip», а просто смотреть на возвращенный буфер и проверять его свойства.
Все таки хотелось бы посмотреть какой был реальный кейс
Скорее всего тут не надо проверять что «вызван метод flip», а просто смотреть на возвращенный буфер и проверять его свойства.
Все таки хотелось бы посмотреть какой был реальный кейс
+1
Есть два подхода к тестированию — BlackBox & WhiteBox. Если проверять только результат выполнения метода — это BlackBox тестирование. Если тестировать с проверкой всех «потрохов» — это WhiteBox подход. Мне позарез надо знать, что был вызван метод flip(), а не ручками выставлены значения. А то ведь всякое бывает.
А реальный кейс… Может Вы и сами скоро с подходящим столкнетесь. А если нет — тем лучше. Значит Вам конкретно эта функциональность PowerMock'а не пригодится. Но ведь важно просто знать, что возможность есть, что бы быть готовым.
А реальный кейс… Может Вы и сами скоро с подходящим столкнетесь. А если нет — тем лучше. Значит Вам конкретно эта функциональность PowerMock'а не пригодится. Но ведь важно просто знать, что возможность есть, что бы быть готовым.
+1
Вот это вот «позарез надо знать» попахивает тем, что вы пытаетесь протестировать слишком много. Это приведёт к тому, что тестов будет слишком много, они будут слишком завязаны на коде, и как следствие, их придётся слишком часто менять при внутренних изменениях в коде, не влияющих на функциональность.
Тестировать надо функциональность, то есть «внешние проявления». Если вам позарез нужно знать, что был вызван метод flip(), значит, подумайте о том, что свалится, если этот метод не был вызван. И на эту ситуацию и напишите тест.
Тестировать надо функциональность, то есть «внешние проявления». Если вам позарез нужно знать, что был вызван метод flip(), значит, подумайте о том, что свалится, если этот метод не был вызван. И на эту ситуацию и напишите тест.
0
Вопрос о подходах unit-тестирования, а так же о том как и где их применять — это тема отдельной статьи и отдельного обуждения… В этой статье был обзор возможностей PowerMock для создания детализированных тестов.
И позвольте Вам возразить. Конечно, Вы частично правы. При таком подходе тесты будут завязаны на коде. И в случае изменений кода потребуется время на изменение тестов. Но это не всегда плохо. Упавший тест — повод задуматься: «А все ли я сделал правильно? Может кто то неспроста до меня сделал именно так?» Плюс ко всему, есть ряд ситуаций, когда тестирование по «внешним проявлениям» не подойдет. Простой пример: есть некий метод, предположим, public void open(), который как мы видим не принимает и не возвращает параметров. Внутри него происходит последовательный вызов нескольких функций из внутренних объектов (возможно так же и статические). Скорее всего, состояние тестируемого объекта изменится. Но, во-первых, это состояние может быть чисто внутренним и не торчать наружу. А следовательно, что бы его проверить необходимо производить танцы с бубном (или использовать PowerMock для удобного доступа к private полям). Во-вторых, в тестируемом методе наверняка важен порядок выполнения внутренних вызовов. Как Вы будете это проверять?
Думать о том, что свалится, если в этом методе что то будет не вызвано — это совсем другая задача, другого теста. Этот же метод вы оставите не протестированным.
Повторюсь, я утверждаю, что все тесты должны быть только такими. Все всегда зависит от ситуации. Просто всегда понимайте что вы делаете и что это может повлечь. Вы тестируете систему детально — будьте готовы к переделке тестов при рефакторинге архитектуры. Вы тестируете систему интеграционно в виде BlackBox — готовьтесь к тому, что внутри система может вести себя не корректно, а ваши тест кейсы просто не способны отловить эту особенность. И никогда не стоит говорить: «я крут и со мной такого не случится». Практика показывает, что случится. Причем в самый не подходящий момент.
И позвольте Вам возразить. Конечно, Вы частично правы. При таком подходе тесты будут завязаны на коде. И в случае изменений кода потребуется время на изменение тестов. Но это не всегда плохо. Упавший тест — повод задуматься: «А все ли я сделал правильно? Может кто то неспроста до меня сделал именно так?» Плюс ко всему, есть ряд ситуаций, когда тестирование по «внешним проявлениям» не подойдет. Простой пример: есть некий метод, предположим, public void open(), который как мы видим не принимает и не возвращает параметров. Внутри него происходит последовательный вызов нескольких функций из внутренних объектов (возможно так же и статические). Скорее всего, состояние тестируемого объекта изменится. Но, во-первых, это состояние может быть чисто внутренним и не торчать наружу. А следовательно, что бы его проверить необходимо производить танцы с бубном (или использовать PowerMock для удобного доступа к private полям). Во-вторых, в тестируемом методе наверняка важен порядок выполнения внутренних вызовов. Как Вы будете это проверять?
Думать о том, что свалится, если в этом методе что то будет не вызвано — это совсем другая задача, другого теста. Этот же метод вы оставите не протестированным.
Повторюсь, я утверждаю, что все тесты должны быть только такими. Все всегда зависит от ситуации. Просто всегда понимайте что вы делаете и что это может повлечь. Вы тестируете систему детально — будьте готовы к переделке тестов при рефакторинге архитектуры. Вы тестируете систему интеграционно в виде BlackBox — готовьтесь к тому, что внутри система может вести себя не корректно, а ваши тест кейсы просто не способны отловить эту особенность. И никогда не стоит говорить: «я крут и со мной такого не случится». Практика показывает, что случится. Причем в самый не подходящий момент.
0
Я кстати согласен с автором. Например, у нас есть код, много где завязанный на Hazelcast, у которого полно статических методов. По уму, надо рефакторить и выносить вызовы Hazelcast в класс-обертку, которую уже легко будет заменить моком. Но мы планируем от него избавиться в будущем, поэтому рефакторить ради тестов я смысла не вижу, если все равно этот код будет убран. Так что в данном конкретном случае проще заюзать PowerMock. Спасибо автору, буду теперь его использовать :)
0
автору спасибо, не знал про такую тулзу. Обычно тестировал методы, где есть статические вызовы путем выноса этих статических вызовов в отдельный метод и затем переопределяя его. Эта штука однозначно облегчит жизнь.
0
Sign up to leave a comment.
PowerMock (+Mockito): новый взгляд на unit-тестирование