Модульное тестирование сервлета, выполняющего вызов URL

#java #servlets #junit #mocking

#java #сервлеты #junit #издевательство

Вопрос:

Я хочу написать модульный тест для класса сервлета, который вызывает веб-службу через java.net.URL.

Я могу легко создавать объекты макетов запросов и ответов для отправки в метод doGet сервлета (используя методы из текста pragmatic programmer в junit), то есть создавать MockHttpServletRequest, MockHttpServletResponse и передавать их в doGet.

Часть, с которой у меня возникли проблемы, — это URL, открытый в сервлете.

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

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

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

  • Пример 1. оберните функцию в класс, который имеет логическое значение testOn и метод setTestMode; junit init может установить для TestMode значение true, по умолчанию false . testOn решает, какой метод вызывать. минус в том, что мне нужен новый класс, похоже, он может выйти из-под контроля.
  • Пример 2. есть два класса, реализующих доступ к сети, один из которых является макетом; пусть junit перезагрузит макет класса, производственный код загрузит обычный класс (или каким-то образом переназначит производственный класс на макет класса). отрицательный: не уверен, как это будет сделано; кажется неуклюжим.
  • Пример 3. создайте класс со статическими полями, указывающими, хочу ли я использовать mocks, и укажите URL-адрес доступа в сервлете на основе значений полей. отрицательный: похоже на глобальные переменные.
  • Пример 4. расширить URL-адрес, чтобы рабочий код работал нормально, если я переключусь только на URL (но java.net .URL является окончательным).

Я не смог найти правильный ответ за утро поисков, поэтому я обратился к коллективной мудрости SO.

Спасибо, Аднан

ps — я должен упомянуть, что мне не нужно использовать java.net .URL, все, что эквивалентно, будет работать.

Ответ №1:

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

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

Такого рода вещи являются каноническим примером для IoC / DI.

Комментарии:

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

2. @user453026 Я бы, наверное, просто попробовал поискать «инверсию управления» или «внедрение зависимостей» плюс «учебник»… однако большинство из них при поиске зависят от фреймворка. Однако большинство из них помогут визуализировать основы, даже не понимая лежащей в их основе структуры.

Ответ №2:

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

Спрячьте вызов веб-службы за интерфейсом. Одна реализация выполняет фактический вызов, в то время как другая является макетом, который вы можете настроить. Если вы не используете какой-либо фреймворк DI (Spring, Guice, EJB / CDI), замените производственную реализацию на mock вручную в тесте.