Введение в тестирование REST API на Go с использованием Resty |
07.08.2020 00:00 |
Автор: Баз Дейкстра (Bas Djikstra) Около года назад я работал в команде, которая, помимо прочего, отвечала за создание и запуск микросервисов, поставляющих данные фронтэнду. Оказалось, что эти сервисы были написаны на Go, языке программирования, о котором я что-то слышал, но с которым никогда не работал. Как тестировщик и инженер-автоматизатор, я получил задачу создания автоматизированных проверок, которые можно было бы встроить в создание билда, и поэтому я решил, что неплохо бы получить новые навыки и изучить новые инструменты, создавая проверки на том же самом языке. Go – язык относительно молодой, появившийся в 2009 году. Это означает, что инструментарий Go не настолько развит, как, скажем, у Java или C#. Несмотря на это, я довольно быстро создал и запустил эти тесты. Недавно я снова наткнулся на Go (не помню, где и когда, но это и не важно) и подумал, что будет хорошей идеей вернуться к этому языку. В этой статье я хочу показать, как писать и запускать тесты REST API на Go. API, которым я буду пользоваться – это вновь Zippopotam.us API. У Go есть встроенная поддержка тестирования – в отличие от языков вроде Java или C#, вам не придется добавлять фреймворк юнит-тестирования в ваш проект. Все, что вам нужно – это импортировать библиотеку testing в код, назвать Go-файл так, чтобы он заканчивался на _test.go, создать метод с именем, начинающимся с Test, запустить go test и вы готовы к работе. Для настройки запросов, перехватов, интерпретации и проверки ответов мне очень пригодилась библиотека Resty. Она довольно похожа на Python-библиотеку requests или C#-библиотеку RestSharp. Вот как на Go с Resty выглядит первый тест – проверка кода статуса ответа для GET-запросов к API в правильном формате:
Обратите внимание, что я не собираюсь объяснять все тонкости Go и его синтаксиса. Если вы хотите узнать больше, я рекомендую эту книгу или тур по Go. Если запустить этот тест командой go test, мы увидим, что он пройден. Каждый тестовый метод берет аргумент типа T (из библиотеки testing), который используется для управления тест-состоянием. Вам может, как мне, показаться странным, что в этом тесте нет ассерта, которого ожидаешь, если знаком с тест-фреймворками вроде JUnit, NUnit или pytest. Причина проста: их не существует в Go-библиотеке testing. У людей, создавших Go, есть на то свои причины, но мне это не особенно нравится. Я предпочитаю использовать ассерты, потому что они делают код более читабельным, а также избавляют меня от самостоятельного создания всех этих if-then-else-конструкций. К счастью, так думаю не только я, поэтому существуют библиотеки сторонних разработчиков, позволяющие писать ассерты. Я выбрал Testify, потому что она также позволяет создавать наборы тестов и использовать методы настройки и очистки схожим с другими языками образом. Вот как будет выглядеть тот же самый тест с использованием предоставленного Testify ассерта:
По-моему, намного лучше. Давайте посмотрим, можем ли мы проверить значение заголовка ответа:
Это довольно прямолинейно. Теперь как насчет извлечения и проверки значения тела ответа? Самый простой способ сделать это в Go – это демаршалировать (преобразовать) тело ответа в struct (структура данных в Go). Чтобы сделать это, для начала нужно определить struct вот так:
Это определяет struct LocationResponse с единственным элементом Country. Тэг json:”country” говорит Go, что в этот элемент должно попадать значение элемента country из JSON-тела ответа. О других элементах в этом ответе не стоит волноваться – они просто не попадут в структуру (если вам нужно проверить и их, то придется добавить их в struct). Теперь мы можем создать тест, который преобразует тело в struct типа LocationResponse, а затем проверить значение элемента Country:
В качестве последнего примера я хочу показать, как создавать метод настройки для достижения начального состояния для всех тестов в наборе. Вот как это сделать, используя Testify и его модуль suite:
Вначале мы создаем struct ZippopotamUsTestSuite, содержащий все общие для всех тестов объекты. В этом случае все, что мне нужно – это Client (класс в Resty) по имени ApiClient (в Go имя переменной идет перед типом данных при определении новой переменной). Затем мы можем написать метод SetupTest() для настройки всех наших тестов, и использовать (suite *ZippopotamUsTestSuite), чтобы существующие тест-методы стали частью определенного нами набора. Для запуска нашего тест-набора нужно создать "обычный" тест-метод и передать созданный набор в метод Testify suite.Run():
Если вы пропустите этот шаг, go test не запустит тест-набор! В целом, учитывая, что я в основном работаю с Java, C# и Python, я считаю, что создание тестов в Go более громоздко, нежели в этих языках. Однако при правильном наборе инструментов вполне возможно писать читабельные и хорошо структурированные Go-тесты, как (я надеюсь) демонстрируют примеры в статье. Я решил исследовать создание тестов (и другого ПО) на Go далее, поэтому начал учить этот язык на этих курсах от Coursera. Они в основном направлены на тех, кто хочет стать Go-разработчиком, и о тестировании там почти не говорят, но я все равно планирую продолжать. Постараюсь делиться советами и тонкостями создания Go-тестов в будущем! Если вы хотите узнать больше о тестировании на Go, то рекомендую статью Алекса Эллиса и обучающий материал. Весь код из статьи можно найти здесь. |