Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Тестирование HTTP-запросов Python: Продвинутое тестирование

Инверсия зависимостей крайне мощная техника, которая работает не только с функциями, но и с объектами. Рассмотрим её глубже на примере HTTP-запросов и познакомимся с таким понятием как "заглушка" (stub).

Предположим, что у нас есть функция, которая анализирует приватные репозитории организации на GitHub и возвращает те, что являются приватными форками (репозитории "отпочкованные" от основного репозитория):

# Библиотека для работы с GitHub API
from github import Github

def get_private_fork_names(username):
    client = Github('access_token')
    # Клиент выполняет запрос на гитхаб и возвращает
    # список приватных репозиториев указанной организации
    repos = client.get_user(username).get_repos(type='private')
    # Оставляем только имена приватных форков
    return [repo.name for repo in repos if repo.fork == True]

Давайте её протестируем. Что мы хотим от этой функции? В первую очередь убедиться, что она работает правильно – возвращает массив имен приватных форков. Идеальный тест выглядел бы так:

def test_get_private_fork_names():
    names = get_private_fork_names('hexlet')
    assert names == # ожидаемый список имен

К сожалению, не всё так просто. Внутри функции выполняется HTTP-запрос. Прикинем, какие проблемы из-за этого могут возникнуть:

  1. Нестабильная сеть может тормозить выполнение тестов и приводить к "фантомным" ошибкам. Тесты будут иногда проходить, иногда нет.
  2. У сервисов подобных github.com установлены ограничения на запросы в секунду, в час, день и так далее. Со 100% вероятностью тесты начнут упираться в эти лимиты. Более того, есть шанс что машина с которой идут запросы, будет заблокирована.
  3. Реальные данные на GitHub не статичны, они могут и, скорее всего, будут меняться, что опять же приведет к ошибкам и необходимости править тесты.

В данном примере HTTP-запрос воспринимается как помеха к тому, чтобы протестировать нашу основную логику. Мы доверяем PyGithub и его библиотеке github, то есть нам не нужно проверять, что она работает правильно (иначе можно свихнуться, если не доверять никому).

Из предыдущего урока мы узнали о нескольких способах выхода из этой ситуации и теперь можем применить один из них.

Инверсия зависимостей

Для использования инверсии зависимости, добавим вторым аргументом функции сам клиент github. Это позволит подменить его в тестах:

from github import Github

# Клиент для работы с Github передаётся снаружи и его можно подменить
def get_private_fork_names(username, client=Github()):
    # Логика повторяется, за исключением работы с клиентом
    repos = client.get_user(username).get_repos(type='private')
    return [repo.name for repo in repos if repo.fork == True]

Нам придётся реализовать фейковый (ненастоящий) клиент, который ведёт себя примерно так же, как и реальный Github, за исключением того, что он не выполняет сетевых запросов. Также нам нужно описать конкретные данные, которые вернут вызовы get_user() и get_repos(). Только в таком случае мы сможем протестировать, что функция get_private_fork_names() работает корректно.

# Структура этого класса описывает только ту часть,
# которая необходима для вызова client.get_user.get_repos
class GithubFake:
    # Здесь мы описываем желаемые данные, которые вернутся в тесте
    def __init__(self, data):
        self.data = data

    # Возвращаем сами себя, чтобы иметь возможность вызвать get_repos() по цепочке
    def get_user(self, name):
        return self

    # Возвращаем переданные в начале данные
    def get_repos(self):
        return self.data

И сам тест с использованием этого клиента:

from github_fake import GithubFake

def test_get_private_fork_names():
    data = # Данные, которые должен вернуть get_repos
    client = GithubFake(data)
    names = get_private_fork_names('hexlet', client=client)
    assert names == # ожидаемый список имен

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


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

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

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
2 февраля 8 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»