На самом деле стоит модульное тестирование клиента API?

38

Это то, что беспокоило меня некоторое время. На самом деле стоит модульное тестирование клиента API?

Допустим, вы создаете небольшой класс, чтобы абстрагировать вызовы API-интерфейса REST. PetShop - очень простой API, и у него есть базовый набор методов:

  • listProducts()
  • getProductDetails(ProductID)
  • addProduct(...)
  • removeProduct(ProductID)

При тестировании мы должны были создать поддельный сервис или смоделировать ответы. Но это кажется излишним; Я понимаю, что мы хотим убедиться, что наши методы не перестают работать из-за опечаток / синтаксических ошибок, но поскольку мы пишем функции, вызывающие удаленные методы, а затем создаем ложные ответы из этих удаленных методов, это выглядит так: пустая трата усилий и что мы тестируем что-то, что не может действительно потерпеть неудачу. Хуже того, если удаленный метод изменится, наши модульные тесты пройдут, пока использование не будет завершено.

Я почти уверен, что что-то упустил, или у меня не тот конец палки, или я не вижу дрова для деревьев. Может кто-нибудь поставить меня на правильный путь?

Филипп Б. Олдем
источник
1
Если бы это был не такой простой API с базовыми методами, вы бы чувствовали себя по-другому? Даже сарай должен стоять до снега.
JeffO

Ответы:

31

Задача удаленного API-клиента - выполнять определенные вызовы - не больше и не меньше. Поэтому его тест должен проверить, что он выполняет эти вызовы - ни больше, ни меньше.

Конечно, если провайдер API изменит семантику своих ответов, ваша система не будет работать. Но это не вина вашего клиентского класса; это то, что можно поймать только в интеграционных тестах. Полагаясь на код, который не находится под вашим контролем, вы отказались от возможности проверять правильность с помощью внутреннего тестирования - это был компромисс, и это цена.

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

Килиан Фот
источник
Ммм, не уверен, что согласен. Вы можете проверить , что вызывается foo()раньше bar(), но это не значит, что вызов foo()раньше bar()- правильная вещь; подобный модульный тест прошел бы, даже если код неправильный. И если это все, что делает клиент, то настройка макетов, которые проверяют, вызывается ли foo()раньше, bar()является относительно проблематичной для чего-то, что можно проверить беглым взглядом на код клиента.
Доваль
1
Вы можете проверить, что add()метод добавляет два числа правильно, но это не означает, что добавление - это то, что нужно сделать в данный момент в алгоритме - add()модульное тестирование пройдет успешно, даже если ваша программа неверна. Если это не то, то ваш levenshteinDistance()метод виноват, а не add()метод. Это точно так же. Смысл разделения кода на методы всегда заключается в том, что каждый метод должен заботиться только об одном .
Килиан Фот
3
Теперь я вижу, где мы не согласны! Если вы полагаетесь на внешний зоомагазин, для меня это означает, что ваша система заканчивается на границе HTTP, поэтому выпущенные вызовы REST являются выходными данными и подлежат тестированию. Если вы считаете, что зоомагазин является частью этого модуля, то да, схема исходящих вызовов является деталью реализации, и модульное тестирование не имеет никакого смысла предписывать что-либо о них.
Килиан Фот
2
«Поэтому его тест должен проверить, что он выполняет эти вызовы» Я думаю, что это та перспектива, которую я не смог увидеть. Благодарность!
Филипп Б. Олдем,
1
Так, например, мой модульный тест может проверить, что, при определенных параметрах, тело запроса, которое он выполняет, является правильным?
Мария Инес Парнисари
9

Краткий ответ:

Все методы должны быть проверены юнитом.

Длинный ответ:

Да. Оно того стоит.

Вот некоторые вещи, которые должны тестировать юнит-тесты этих методов вызова API:

  • То, что вы передаете правильно сформированные или правильные параметры вызовам API.
  • То, что вы реагируете соответствующим образом на определенные типы данных, возвращаемых API (поддельные или нет), например, может быть, когда API возвращает пустую строку, ваш метод должен вернуть значение по умолчанию (просто пример)
  • То, что методы вызывающей стороны ведут себя правильно, когда вызовы API выдают ошибку

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

Тулаинс Кордова
источник
Вы говорите «издевались или нет» ... так можно ли тестировать реальный API? Можно ли назвать это интеграционным тестом, хотя он выглядит как модульный тест? Или есть еще одна вещь, чтобы назвать это? Я бы хотел проверить, что мой API-упаковщик делает то, что говорит, как-то ...
Дэн Розенстарк
1
@ DanRosenstark Я думаю, в случае, если служба API не подвергается насмешкам, это интеграционный тест.
Тулаинс Кордова
Разве вы не узнаете через 5 секунд, правильно ли вы возвращаете данные при фактическом вызове API? Поскольку ложные срабатывания API не являются реальными вызовами, единственный способ, которым они потерпят неудачу, - это если они изменят API ... в этом случае ваши пробные тесты пройдут, но реальные вызовы не пройдут. Кажется бессмысленным
Мэтт
5

Это не будут модульные тесты, потому что вы тестируете вход и выход вашей системы, скорее ограниченные тесты интеграции.

Будьте очень осторожны, когда говорите: «Это кажется пустой тратой усилий, и мы тестируем что-то, что не может действительно потерпеть неудачу» - оно может потерпеть неудачу, оно потерпит неудачу, возможно, оно потерпит неудачу способами, которые вы не можете предвидеть, неудачи будут хуже, если у вас нет тестов на месте.

Ошибка, которую вы делаете здесь, состоит в том, что вы сделали изобретение колес: звонки в удаленные сервисы и API-интерфейсы - очень распространенный сценарий, поэтому есть несколько довольно хороших инструментов, которые помогут вам проверить это. В прошлый раз, когда я работал над приложением, которое подключалось к удаленным сервисам, я использовал SoapUIкоторый может смотреть на службу и делать ложные вызовы этой службы или вести себя как локальная копия сервера, с которым вы можете делать тестовые вызовы и отслеживать запросы и ответы. Установка заняла несколько минут, а также очень быстро обновилась, если изменился удаленный интерфейс. Я не использовал его в сценарии REST, но даже если он не работает для этого (или, возможно, кто-то читает этот ответ в будущем, когда существуют лучшие инструменты), вы сможете найти инструмент, который может макетировать сервис для вас, и когда придет время для развертывания вашего кода, вы будете рады, что вы сделали.

glenatron
источник