Тестирование клиента REST на сервере REST. Как сделать светильники?

10

При написании модульных тестов обычно используются фиксаторы: мало тестируемых данных, поэтому мы можем сказать: 1. Получить все клиенты должны включать Вилли Вонка. 2. Удалите клиента 3, и теперь клиенты не должны включать Вилли Вонка больше.

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

Но как насчет того, когда мы отделили REST-сервер от REST-клиента?

Мы хотим убедиться, что наш REST-клиент не только правильно читает, но и правильно создает, обновляет и удаляет.

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

Предполагая, что у меня есть тестовый сервер REST, обслуживающий только приборы. Вся природа HTTP без сохранения состояния означает, что было бы трудно отправлять сообщения типа «BEGIN TRANSACTION» и «ROLLBACK TRANSACTION» или «RELOAD FIXTURES», верно?

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

Какие-либо предложения?

Сиверс
источник
Возможно, поскольку это тестовый сервер, у вас может быть конечная точка, которая будет перезагружать приборы?
Дэвид Рэдклифф
Если ваша основная проблема заключается в том, чтобы вернуть тестовый сервер в предопределенное состояние, почему бы вам не добавить какие-либо специальные функции тестирования, такие как «RELOAD TESTDATA», в ваш API остальных для выполнения того, что вы хотите? Конечно, вы должны убедиться, что такие вызовы API не доступны в производстве.
Док Браун,

Ответы:

7

Программные системы в идеале имеют четко определенные системные границы и интерфейсы между ними. Службы REST являются хорошими примерами этого.

С этой целью, я рекомендовал бы против делать то , что вы пытаетесь сделать.

В частности:

Мы хотим убедиться, что наш REST-клиент не только правильно читает, но и правильно создает, обновляет и удаляет.

Вместо этого я бы предложил:

  • Построение тестов для вашего клиента REST, чтобы убедиться, что он ведет себя правильно, с учетом конкретного ввода и вывода. Учитывайте хорошие (ожидаемые) и плохие (неожиданные) значения.

  • Построение тестов для вашей службы REST (если вы управляете ею), чтобы вести себя в соответствии с ее назначением

  • Держите тесты близко к их проблемной области, чтобы они могли помочь в разработке и разработке того, что важно в этом контексте

briandoll
источник
3
Вы совершенно случайно отбрасываете идею интеграционных тестов. Я не думаю, что этот подход основан на практике.
Febeling
Спасибо всем за полезные предложения. Также в Твиттере я получил отличные предложения попробовать Ruby gem «webmock» и аналогичные, чтобы высмеивать ответ сервера REST API. Я также согласен с «febeling» в том, что то, что я описываю, похоже на интеграционный тест, поэтому я рассмотрю это отдельно. Еще раз спасибо всем. - Дерек
Сиверс
Насмешка над API - отличный способ решить проблему. Но как сделать так, чтобы этот поддельный API == реальный API?
FrEaKmAn
4

Здесь нужно учитывать два угла:

  • Вы тестируете свой код или сантехнику? Предполагая, что вы используете хорошо известные сервис и клиентский стек, вы, вероятно, можете спокойно предположить их тестировщиков, и тысячи пользователей, как правило, будут следить за тем, чтобы в фундаменте не было фундаментальной ошибки.
  • Почему ваши тесты не являются идемпотентными? Создайте способ записи непроизводственных данных или записи в другую конечную точку. Выберите некоторый предсказуемый образец именования. Предварительно загрузите остальные серверные БД перед тестами. И, возможно, есть еще несколько способов сделать это - метод действительно тактический и должен зависеть от характера приложения.
Уайетт Барнетт
источник
2

Я думаю, что подделка ответов сервера REST - лучший способ проверить клиента.

Для Ruby есть гем FakeWeb, который вы можете использовать для создания ложных ответов - https://github.com/chrisk/fakeweb .

Также в JavaScript вы можете использовать что-то вроде Sinon.JS, что дает вам поддельный сервер - http://sinonjs.org/docs/#fakeServer .

laktek
источник
1

Как уже говорили другие, если вы тестируете клиента, вам не нужно заходить так далеко, как создавать, удалять и т. Д. На сервере. Большую часть времени вам даже не нужно издеваться над сервером вообще. Вам действительно нужно только убедиться, что вы делаете правильные запросы и правильно обрабатываете ответы, написаны ли они на Ruby, Python, PHP или чем-то еще, в какой-то момент ваш клиент, вероятно, собирается использовать метод из библиотеки HTTP, чтобы сделать запрос, и этого достаточно, чтобы смоделировать этот метод, проверить, как он вызывается, и вернуть результат теста.

Возьмите гипотетический клиент Python, который использует urllib2для выполнения запросов. Возможно, у вас есть какой-то метод в клиенте, давайте его назовем get(), который имеет вызов urllib2.Request(). Вам действительно нужно высмеивать вызов вашего класса get().

@patch('your.Client.get')
def test_with_mock(self, your_mock):
    your_mock.return_value({'some': 'json'})
    test_obj = your.Client.get_object(5)
    your_mock.assert_called_with('/the/correct/endpoint/5')

В этом очень упрощенном примере библиотека Python Mock используется для проверки гипотетического your.Clientкласса с помощью get_object()метода, который генерирует правильный URL-адрес для получения чего-либо из некоторого API. Чтобы сделать запрос, клиент вызывает свой get()метод с этим URL. Здесь этот метод является поддельным ( your.Client.get«исправлен», так что он находится под контролемyour_mock ), и тест проверяет, была ли запрошена правильная конечная точка.

Метод mocked возвращает сконфигурированный ответ JSON ( your_mock.return_value), который должен обработать клиент, и вы сделаете дополнительные утверждения, чтобы проверить, что он обработал ожидаемые данные ожидаемым образом.

Шон Редмонд
источник
Но как вы уверены, что когда вы делаете «правильный» запрос, это действительно правильный (в производстве) запрос? Потому что, если я пойму ваше предложение, если API изменится или сломается, ваши тесты все равно будут работать. В то время как в производстве это совсем другая история.
FrEaKmAn
1

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

Подход с фикстурами такой же неуклюжий и неуклюжий, но он используется по умолчанию для некоторых фреймворков, например, Rails, и он уже поддерживается. Им нужен абстрактный контрольный пример или что-то подобное для подготовки базы данных с фиксаторами. (Остерегайтесь необычного именования категорий тестов в Rails, юнит-тесты с фиксаторами БД, строго говоря, также являются интеграционными тестами.)

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

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

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

febeling
источник
1

Monkey Patch

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

Льготы

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

компромиссы

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