Мы пытаемся спроектировать нашу систему так, чтобы она была тестируемой, и в большинстве случаев она была разработана с использованием TDD. В настоящее время мы пытаемся решить следующую проблему:
В разных местах нам необходимо использовать статические вспомогательные методы, такие как ImageIO и URLEncoder (оба являются стандартными Java API) и различные другие библиотеки, которые состоят в основном из статических методов (например, библиотеки Apache Commons). Но крайне сложно протестировать те методы, которые используют такие статические вспомогательные классы.
У меня есть несколько идей для решения этой проблемы:
- Используйте фиктивный фреймворк, который может имитировать статические классы (например, PowerMock). Это может быть самое простое решение, но почему-то хочется сдаться.
- Создайте инстанцируемые классы-оболочки вокруг всех этих статических утилит, чтобы их можно было внедрить в классы, которые их используют. Это звучит как относительно чистое решение, но я боюсь, что в итоге мы создадим очень много этих классов-обёрток.
- Извлеките каждый вызов этих статических вспомогательных классов в функцию, которую можно переопределить, и протестируйте подкласс класса, который я на самом деле хочу протестировать.
Но я продолжаю думать, что это просто должна быть проблема, с которой сталкиваются многие люди при выполнении TDD - поэтому уже должны быть решения этой проблемы.
Какова лучшая стратегия для того, чтобы классы, которые используют эти статические помощники, тестировались?
источник
Ответы:
(Боюсь, здесь нет «официальных» источников - это не так, как есть спецификация, как хорошо тестировать. Только мои мнения, которые, надеюсь, будут полезны.)
Когда эти статические методы представляют подлинные зависимости, создайте оболочки. Так что для таких вещей, как:
... имеет смысл создать интерфейс.
Но многие из методов в Apache Commons, вероятно, не должны быть обмануты / фальсифицированы. Например, возьмите метод, чтобы объединить список строк, добавив запятую между ними. Нет смысла насмехаться над этим - просто позвольте статическому вызову делать свою обычную работу. Вы не хотите или не должны заменить нормальное поведение; Вы не имеете дело с внешним ресурсом или чем-то, с чем трудно работать, это просто данные. Результат предсказуем, и вы никогда не захотите, чтобы он был чем-то иным, чем он все равно даст
Я подозреваю, что, удалив все статические вызовы, которые на самом деле являются удобными методами с предсказуемыми, «чистыми» результатами (такими как base64 или URL-кодирование), а не точками входа в целый большой беспорядок логических зависимостей (например, HTTP), вы обнаружите, что это полностью практично делать правильные вещи с настоящими зависимостями.
источник
Это, безусловно, сомнительный вопрос / ответ, но за то, что он того стоил, я подумал, что я добавлю свои два цента. С точки зрения метода стиля TDD 2, безусловно, подход, который следует за буквой. Аргумент для метода 2 заключается в том, что если вы когда-нибудь захотели заменить реализацию одного из этих классов, скажем,
ImageIO
эквивалентной библиотеки, то вы могли бы сделать это, сохраняя уверенность в классах, которые используют этот код.Однако, как вы упомянули, если вы используете много статических методов, то в итоге вы напишете много кода-обертки. Это не может быть плохо в долгосрочной перспективе. С точки зрения ремонтопригодности, безусловно, есть аргументы для этого. Лично я бы предпочел такой подход.
Сказав это, PowerMock существует по причине. Это довольно хорошо известная проблема, которая заключается в том, что тестирование с использованием статических методов является очень болезненным, поэтому возникла PowerMock. Я думаю, что вам нужно взвесить ваши варианты с точки зрения того, сколько работы потребуется, чтобы обернуть все ваши вспомогательные классы по сравнению с использованием PowerMock. Я не думаю, что использование PowerMock «сдалось» - я просто чувствую, что обертывание классов дает вам большую гибкость в большом проекте. Чем больше публичных контрактов (интерфейсов) вы можете обеспечить тем чище разделение между намерением и реализацией.
источник
В качестве справки для всех, кто также имеет дело с этой проблемой и сталкивался с этим вопросом, я собираюсь описать, как мы решили решить эту проблему:
Мы в основном идем по пути, обозначенному как # 2 (классы-обертки для статических утилит). Но мы используем их только тогда, когда это слишком сложно, чтобы обеспечить утилиту необходимыми данными для получения желаемого результата (то есть, когда нам абсолютно необходимо смоделировать метод).
Это означает, что нам не нужно писать оболочку для простой утилиты, такой как Apache Commons
StringEscapeUtils
(потому что строки, которые им нужны, могут быть легко предоставлены), и мы не используем mock для статических методов (если мы думаем, что нам может понадобиться, пришло время написать класс обертки, а затем макет экземпляра обертки).источник
Я бы протестировал эти классы, используя Groovy . Groovy просто добавить в любой проект Java. С его помощью вы можете легко смоделировать статические методы. См. Mocking Static Methods with Groovy для примера.
источник
Я работаю в крупной страховой компании, и наш исходный код занимает до 400 МБ чистых java-файлов. Мы разрабатывали все приложение, не задумываясь о TDD. С января этого года мы начали тестирование Junit для каждого отдельного компонента.
Лучшим решением в нашем отделе было использование объектов Mock в некоторых методах JNI, которые зависели от системы (написаны на C), и поэтому вы не могли точно оценить результаты каждый раз в каждой ОС. У нас не было другого выбора, кроме как использовать поддельные классы и конкретные реализации методов JNI специально для тестирования каждого отдельного модуля приложения для каждой поддерживаемой нами ОС.
Но это было действительно быстро и до сих пор работало довольно хорошо. Я рекомендую это - http://www.easymock.org/
источник
Объекты взаимодействуют друг с другом для достижения цели, когда вам сложно протестировать объект из-за среды (конечная точка веб-сервиса, слой дао, обращающийся к БД, контроллеры, обрабатывающие параметры запроса http) или вы хотите протестировать свой объект изолированно, затем Вы издеваетесь над этими объектами.
необходимость в насмешливых статических методах - это неприятный запах, вы должны разрабатывать свое приложение более объектно-ориентированным, а статические методы утилиты модульного тестирования не вносят большой пользы в проект, класс-оболочка - хороший подход в зависимости от ситуации, но попробуйте проверить те объекты, которые используют статические методы.
источник
Иногда я использую вариант 4
Что-то вроде этого.
Что мне нравится в этом подходе, так это то, что он поддерживает статические служебные методы, что мне кажется правильным, когда я пытаюсь использовать класс в коде.
источник