{"id":14287,"url":"\/distributions\/14287\/click?bit=1&hash=1d1b6427c21936742162fc18778388fc58ebf8e17517414e1bfb1d3edd9b94c0","title":"\u0412\u044b\u0440\u0430\u0441\u0442\u0438 \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0434\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u0437\u0430 \u0433\u043e\u0434","buttonText":"","imageUuid":""}

Тестирование на стороне бекенда

План статьи.

  1. Вводная часть и описание видов тестирования на стороне бекенда.

  2. Описание окружения для тестирования и что будет проверятся в ходе тестирования

  3. Описание тестирования контроллера (проверка методов через юнит тестирование и e2e тестирование через эмуляцию запросов)

  4. Описание тестирования сервиса

  5. Тестирование пайпов, правил валидации и гвардов

  6. Выводы

Вводная часть и описание видов тестирования на стороне бекенда

Всем привет, меня зовут Александр, я являюсь фронтенд разработчиком с 4-х летним опытом работы. В этой статье я хочу рассказать о своем опыте работы на стороне бекенда в своих пет проектах. Ранее в статьях я уже описывал, что свой путь в программирование начинал с языка программирования php и это в свою очередь оставило на мне свой отпечаток и по сей день. В данный момент времени, в качестве бекенда на своих пет проектах у меня используется node js, а конкретнее nestjs.

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

Перед началом статьи хочу дать описание, что для меня обозначают разные виды тестирования на стороне бекенда. Всего существует 3 вида тестирования:

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

  • Интеграционные тесты — это проверка интеграции между модулями. Например, есть некие сущности на стороне бекенда, например статьи и база данных, в которой хранятся данные об этих статьях. Так вот, задача интеграционных тестов проверить место соединения этих двух сущностей, чтобы данные удачно сохранялись, удалялись и были получены. Такого рода тесты уже тяжело писать и в дальнейшем поддерживать, поэтому я их не пишу.
  • E2e тесты — это тесты, которые проверяют web приложение от начала до конца, само название тестов говорит о себе. В моем понимании, самый простой пример e2e тестов является проверка получения данных из базы данных, либо какая-либо другая операция с ними, передача их на сторону ui и отрисовка полученных данных на стороне клиента. Тесты такого рода уже пишут профессиональные тестировщики, потому что они еще более тяжелые в написании и поддержке, чем интеграционные. В основном их применяют в больших команиях наподобие банков или тому подобное.

Описание окружения для тестирования и что будет проверятся в ходе тестирования

Для тестирования бекенда я буду использовать настроенное окружение в самом фреймворке nest.js — это jest. C этим окружением я хорошо знаком, потому что использую его для проверки своих ui компонентов. Что будем проверять в процессе тестирования: контроллер, сервисы, пайпы, правила.

Описание тестирования контроллера

Контроллер тестируется на наличие вызова самих методов, потому что он в себе не хранит никакую логику, его задача принять в себя данные и передать их сервису, который их далее обработает.

Как мы видим по картинке ниже «пример использования контроллера» контроллер принимает в себя запрос с параметрами и далее передает информацию в сервис. В самом сервисе уже происходит обработка данных.

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

На картинке ниже «Пример реализации моковых данных в тесте для проверки контроллера» видно следующее:

  • на 11-й строке мокается гвард;

  • на 20-й и 28-й строке мокаются сервисы;

  • на 33-й строке создаем экземпляр переменной под контроллер.

Пример использования контроллера

Пример реализации моковых данных в тесте для проверки контроллера

На картинке «Инициализация данных для тестирования контроллера» с 35-й по 55-ю строку проходит инициализация тестовых данных для прохождения тестов в файле. На 57-й строке переменной задается значение контроллера в переменную, которая была ранее инициализирована на 33-й строке, чтобы можно было напрямую вызывать его методы.

Инициализация д анных для тестирования контроллера

Итого, по ранее описанным примерам, мы имеем заданные моки и инициализированный тестовый модуль, в рамках которого можно провести юнит тестирование экшенов контроллера. На картинке ниже «Пример юнит тестов для экшена контроллера» приведен пример тестирования экшенов контроллера.

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

Пример юнит тестов для экшена контроллера

Все что было выше описано относится к юнит тестированию, но т. к. контроллеры являются по сути входной точкой запроса, то на них еще пишут и e2e тесты, как упоминается выше, я не пишу такие тесты, но хочу привести пример их реализации с замоканными вызовами. На картинке «Пример написания теста из e2e тестирования» ниже приведен пример написания теста из e2e тестирования. В нем примечательно то, что в тесте можно автоматически проверить ответ и если тест упадет, то сразу можно локализовать ошибку. Но, как я упоминал выше — такие тесты тяжело поддерживать.

Пример написания теста из e2e тестирования

Описание тестирования сервиса

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

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

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

Инициализация тестового модуля для тестирования сервиса

Далее проверяем работу каждого метода сервиса, это можно увидеть на картинке ниже «Пример юнит тестов для сервиса».

Пример юнит тестов для сервиса

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

Тестирование пайпов, правил валидации и гвардов

Пайпы и правила валидации в nest.js представляют собой просто классы, которые выполняют роль валидации или преобразования данных до того, как они попадут в контроллер.

На картинке «Пример теста для пайпа» увидим, что для теста создается экземпляр класса с пайпом и после этого проверяем на нужные нам сценарии.

Теперь давайте рассмотрим пример посложней — это тестирование правил. По факту правила это те же классы, как пайпы, но в них чаще используется сервис модуля. Как тогда в этом случае произвести тестирование правила? Очень просто — для этого необходимо замокать сервис, который импортируется в правило, а также все данные, которые необходимы для инициализации данного сервиса. На картинке «Пример юнит тестирования правила» ниже можем увидеть пример тестирования правила, когда необходимо замокать данные из сервиса и сам сервис.

Пример теста для пайпа

Пример юнит тестирования правила

Теперь давайте рассмотрим тестирование гвардов. По факту гварды это те же самые классы, как и пайпы с валидаторами. Отличие состоит в том, что на вход гвардом необходимо давать аргумент контекста, который во время тестирования заменяется замоканным классом. Пример реализации тестового класса приведен ниже на картинке «Замоканный класс для гварда». В остальном реализация файла теста идентична примеру из тестирования правила, которое описана выше.

Замоканный класс для гварда

Вывод

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

0
Комментарии
-3 комментариев
Раскрывать всегда