Как протестировать приложение Java, работающее непосредственно на внешнем API - PullRequest
4 голосов
/ 21 ноября 2010

После прихода из мира Ruby у меня возникли небольшие проблемы с выполнением TDD на Java.Самая большая проблема возникает, когда у меня есть приложение, которое просто взаимодействует с внешним API.

Скажем, я хочу просто получить некоторые данные из Календаря Google или 5 твитов от какого-то пользователя Twitter и отобразить его.

В Ruby у меня нет никаких проблем, потому что Я могу напрямую подключить библиотеку API в тестах , но у меня нет такой опции в Java.

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

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

# do I have to abstract everything just to do this in Java?
Twitter.stub!(:search)

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

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

Я что-то упустил, или этопросто способ тестирования в мире Java?

Ответы [ 5 ]

3 голосов
/ 21 ноября 2010

Я бы сделал это с помощью внешнего API.

Итак, как вы уже сказали, у вас будет интерфейс и два класса: реальный и фиктивная реализация.

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

3 голосов
/ 21 ноября 2010

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

  1. различные аспекты класса в разных контекстах и ​​
  2. различные реализации одного и того же контракта без изменения кода клиента.

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

Одна из самых важных книг о лучших практиках Java - Эффективная Java от Джошуа Блоха . Я настоятельно рекомендую вам прочитать это. В этом контексте наиболее важной частью является Элемент 52: Обращайтесь к объектам по их интерфейсам . Цитата:

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

А если вы пойдете дальше (например, при использовании внедрения зависимостей), вы даже не вызовете конструктор.

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

0 голосов
/ 26 ноября 2010

Вы можете"обезьяньим патчем" API в Java.Сам язык Java не предоставляет конкретных средств для этого, но JVM и стандартные библиотеки предоставляют.В Ruby разработчики могут использовать для этого библиотеку Mocha .В Java вы можете использовать библиотеку JMockit (которую я создал из-за ограничений в старых инструментах насмешек).

Вот пример теста JMockit, эквивалентный тесту test_should_calculate_value_of_unshipped_orders, доступному в Мокская документация :

   @Test
   public void shouldCalculateValueOfUnshippedOrders()
   {
      final Order anOrder = new Order();
      final List<Order> orders = asList(anOrder, new Order(), new Order());

      new NonStrictExpectations(Order.class)
      {{
         Order.findAll(); <em>result</em> = orders;
         anOrder.getTotalCost(); <em>result</em> = 10;
      }};

      assertEquals(30, Order.unshippedValue());
   }
0 голосов
/ 24 ноября 2010

Мокито более удобен и похож на ваши рубиновые издевательства.

0 голосов
/ 21 ноября 2010

Я понимаю, что вам нужны Макеты объектов .

Как вы уже описали, один из способов создания "тестовых версий" объектов - это реализация общего интерфейса ииспользуя его.

Однако, чего вам не хватает, так это просто расширить класс (при условии, что он не объявлен final) и переопределить методы, которые вы хотите имитировать.(NB: возможность сделать это является причиной того, что для библиотеки считается плохой формой объявить свои классы окончательными - это может значительно усложнить тестирование.)

Существует ряд библиотек Java, которые нацелены наоблегчение использования объектов Mock - вы можете посмотреть на Mockito или EasyMock .

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