Пишем API gem: как написать тесты для внешнего API
В прошлой статье мы разобрались как совладать с Hypermedia API и зачем оно вообще нужно. С момента написания той статьи я успел добавить все API точки в код гема, а так же внёс некоторые мелкие фиксы. Вот ссылка на все изменения с того момента: 8056904. c9088e6.
В этой статье мы исправим главный недостаток гема GrooveHQ: отсутствие тестов. Тестирование кода, зависящего от внешнего API – неприятная, но часто встречающаяся задача. Я постараюсь упростить её как можно сильней.
Если тебя мучает вопрос “почему не TDD? А как же red green refactor?”, то прочитай статью про написание первых тестов платформы mkdev, там я объясняю причины моей не любви к этому подходу.
Настройка тестового окруженияВ качестве библиотеки для тестов я снова выбираю Rspec – особых преимуществ кроме привычности и бо`льшей популярности я не вижу, но и их достаточно чтобы сделать выбор. Обновим Gemfile:
Внимательный читатель спросит: а почему я добавил гем в Gemfile, а не в gemspec? Отвечаю: просмотрев исходники популярных гемов и пару статей я пришёл к выводу, что гемы для тестов не являются настоящей зависимостью гема, а значит их не стоит добавлять в gemspec.
Дальше нужно добавить папку spec и файл spec/spec_helper.rb :
Можно переходить к тестам.
Выявление недоработок в коде тестамиПервый же написанный мой тест выловил небольшой косяк в коде:
Оказывается, если в качестве данных передать пустую строчку, то старая версия кода выдаст исключение. Обновленный код такой проблемой не страдает и позволяет тесту снова стать зелёным:
Воодушевившись первой победой, добавляю ещё несколько тестов для GrooveHQ::Resource :
Заодно нашёл ещё один баг, смотри полный коммит со всеми тестами на данный момент: f1b5da4. Немного подумав, я решил разбить тесты этого класса на контексты, где каждый контекст посвящён отдельному методу: ed0cd7a.
Лирическое отступлениеПрежде чем я продолжу писать тесты, хочется просто поговорить за жизнь. Во-первых, я решил не покрывать тестами все методы, отвечающие на конкретные API-точки. Например, вот такой метод:
Единственный тест, который я могу здесь придумать – это сделать stub результата HTTP-запроса и сравнить, что вызов этого метода возвращает результат этого stub’а. Получается какой-то странный тест. А таких методов сейчас 23. Засорять папку с тестами такими вот бестолковыми проверками, которые потеряют актуальность после малейшего обновления API смысла нет.
Таким образом, мне остаётся только написать тесты на метод GrooveHQ::Client::Connection#parse_data и можно считать 80% важного кода покрытым тестами.
Тестируем запросы к APIСразу же возникла одна концептуальная проблема: метод #parse_data помечен как private , а значит я не могу вызывать его напрямую, только при помощи send. Да и в целом, одна из особенностей приватных методов в том, что их не нужно тестировать напрямую.
К сожалению, это означает что нам не обойтись без стабов (stubs), так как все публичные методы, которые я могу вызвать выполняют запрос к API. Значит, нужно “стабать” эти запросы и вместо проведения запроса просто возвращать готовый JSON ответ. Для этой задачи я буду использовать гем WebMock, который подключил в коммите 2bf8b92.
Здесь вместо разбивки на контексты по методам, я сделал контекст для каждого типа ответов от API. Вот, например, тест для самого простого варианта – один корневой ключ со всеми атрибутами ресурса внутри:
Строчкой stub_request(:get, "https://api.groovehq.com/v1/tickets/1").to_return(body: response) я говорю: “вместо проведения настоящего запроса по этому адресу просто возвращай мне сразу response ”. Тест получился достаточно объёмным, поэтому за всеми спеками нужно идти и смотреть коммит 69e56b4.
TravisCIНа этом, поидее, можно было бы и завершить написание тестов. Но я посчитал хорошей идеей добавить к проекту Travis CI – самое популярное CI решение для OpenSource проектов. Добавляется он просто – созданием файла .travis.yml и следованием документации.
В результате после каждого коммита прогоняются тесты и все, кто пользуется гемом всегда могут проверить работоспособен ли он. GrooveHQ гем, например, работоспособен.
Что дальше?На данный момент гем feature complete – можно подключать его к своему приложению и использовать для удобного обращения к любым API точкам GrooveHQ. Все нуждающиеся в этом участки кода покрыты тестами, и у гема даже есть красивый значок от Трэвиса, рапортующий о том, что эти тесты проходят. Впринципе, на этом можно и остановиться. Но вместо этого тебя ждут ещё одна статья, а меня – ещё немного работы по улучшению гема.
Во-первых, в следующей статье мы рассмотрим метапрограммирование в Ruby. Мне хочется использовать что-то подобное: client.ticket(2).state вместо client.ticket(2).rels[:state].get.data .
Во-вторых, нужно куда-то этот гем опубликовать, а ещё написать к нему документацию.
Так что впереди по-прежнему много интересного. Если на твой взгляд в геме не хватает чего-то ещё – пиши в комментариях и, возможно, появится необходимость в ещё нескольких статьях ;-)
Мы рассказываем, как стать более лучшим разработчиком, как поддерживать и эффективно применять свои навыки. Информация о вакансиях и акциях эксклюзивно для более чем 8000 подписчиков. Присоединяйся!