Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Code
  2. TDD
Code

Разработка через тестирование на практике

by
Difficulty:IntermediateLength:MediumLanguages:

Russian (Pусский) translation by Alexey Pyltsyn (you can also view the original English article)

Что такое разработка через тестирование?

Разработка через тестирование (test-driven development, TDD) просто означает, что вы сначала пишете свои тесты. Вы заранее создаете ожидания для правильного кода, прежде чем вы даже напишите хотя бы одну строку бизнес-логики. TDD не только помогает убедиться, что ваш код правильно работает, но он также помогает писать меньше по размеру функции, заниматься рефакторингом кода без нарушения функциональности, а также лучше понять вашу проблему.

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

Построение HTTP-клиента с TDD

Что мы будем создавать

Мы будем пошагово создавать простой HTTP-клиент, который абстрагирует различные HTTP-методы. Чтобы сделать рефакторинг гладким, мы будем следовать методам TDD. Для тестирования мы будем использовать Jasmine, Sinon и Karma. Для начала работы скопируйте файл package.json, karma.conf.js и webpack.test.js из примера проекта, либо просто склонируйте пример проекта из репозитория на GitHub.

Будет легче, если вы понимаете, как работает новый API Fetch, но примерам должны быть легкие для понимания. Для тех, кто не работал с API Fetch, XMLHttpRequest — лучшая альтернатива ему. Он упрощает взаимодействие с сетью и хорошо работает с промисами.

Обертка над GET

Сначала создайте пустой файл в src/http.js и соответствующий тестовый файл src/__tests__/http-test.js.

Давайте создадим тестовое окружение для этого сервиса.

Мы используем как Jasmine, так и Sinon — Jasmine, чтобы определить тестовые сценарии, а Sinon, чтобы утверждать и создавать шпионов для объектов. (Jasmine имеет свой собственный способ создать шпионы и заглушки в тестах, но мне больше нравится API в Sinon.)

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

Начнем с неудачного тестового примера:

Вызовите исполнитель тестов с помощью karma start. Тесты, очевидно, будут терпеть неудачу, поскольку в http нет метода get. Давайте это исправим.

Если вы сейчас запустите свои тесты, вы увидите сообщение об ошибке Expected [object Response] to equal Object({ }). Объект потока — это ответ. Потоковые объекты, как следует из названия, представляют собой поток данных. Для получения данных из потока, сначала необходимо прочитать поток, используя некоторые из его вспомогательных методов. На данный момент мы можем предположить, что поток будет JSON и десериализуем его, вызвав response.json().

Теперь наш тестовый набор должен быть зеленым.

Добавление параметров из строки запроса

До сих пор метод get просто делал простой вызов без каких-либо параметров запроса. Давайте напишем неудачный тест, чтобы увидеть, как он должен работать с параметрами запроса. Если мы передадим { users: [1, 2], limit: 50, isDetailed: false } в качестве параметров строки запроса, наш HTTP-клиент должен сделать вызов по URL-адресу /api/v1/users/?users=1&users=2&limit=50&isDetailed=false.

Теперь, когда у нас есть тест, давайте расширим наш метод get для обработки параметров запроса.

Если параметры присутствуют, мы формируем строку запроса и добавляем ее к URL-адресу.

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

Обработка мутаций

GET — это, пожалуй, самый простой из HTTP-методов для реализации. GET также идемпотентный метод, что означает, что его нельзя использовать для любых мутаций (изменений). Обычно метод POST предназначен для обновления некоторых записей на сервере. Это означает, что POST-запросы нуждаются в определенных способах защиты по умолчанию, например токен CSRF. Подробнее об этом в следующем разделе.

Начнем с создания теста для простого запроса POST:

Метод POST очень похож на GET. Он использует свойство options, где вы можете определить заголовки, тело и, самое главное, method. Метод также выражается глаголом, в данном случае — "post".

Допустим, что теперь тип контента — JSON, и с этого начинается реализация запроса POST.

На данный момент наш метод post очень примитивен. Он не поддерживает ничего, кроме запроса JSON.

Альтернативные типы содержимого и CSRF-токены

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

Для этого начните с передачи объекта options в качестве третьего параметра в наш метод.

Когда мы предоставим options как {contentType: http.HTTP_HEADER_TYPES.text,includeCsrf: true}, он должен соответствующим образом устанавливать заголовок содержимого и заголовки CSRF. Давайте обновим функцию post для поддержки этих новых параметров.

Обратите внимание, что получение токена CSRF — это деталь реализации. Обычно это часть вашего cookie-сеанса, и вы можете извлечь его оттуда. Я не буду касаться этого дальше в этой статье.

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

Кодирование форм

Сейчас наш метод post формируется, но это все еще довольно тривиально при отправке тела. Вам придется отправлять ваши данные по-разному в зависимости от типа содержимого. При работе с формами мы должны кодировать данные как строку перед отправкой по проводке.

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

Посмотрите на это! Наши тесты все еще проходят даже после рефакторинга основного компонента.

Обработка PATCH-запросов

Другим широко используемым HTTP-методом является PATCH. Теперь PATCH — это вызов на изменение данных, что означает, что подпись этих двух действий очень похожа. Это единственная разница в HTTP-методе. Мы можем повторно использовать все тесты, которые мы писали для POST, но с простым изменением.

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

Теперь, когда все наши тесты POST проходят, все, что осталось, это добавить еще один метод для patch.

Просто, не так ли? В качестве упражнения попробуйте самостоятельно добавить запрос PUT или DELETE. Если у вас возникли трудности с реализацией, не стесняйтесь обращаться к репозиторию.

Когда нужен TDD?

Сообщество разделяется в этом вопросе. Некоторые программисты бегут и прячутся, когда они слышат слово TDD, в то время как другие живут им. Вы можете достичь некоторых полезных эффектов TDD, просто имея хороший набор тестов. Здесь нет правильного ответа. Это все о том, насколько вы комфортно относитесь к своей команде с вашим подходом.

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

Заключение

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

Спасибо за чтение и дайте нам знать, что вы думаете в разделе комментариев.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.