Python unittest, pytest fixture – замокированный объект не передается в тестируемую функцию и создает новый объект вместо этого

Вопрос или проблема

Целью является тестирование модуля git_commons.py, ниже приведен код из файла. Я не могу передать фикстуру pytest в тестовую функцию. Более подробная информация представлена ниже.

import json
from github import Github
import logging
import boto3
import os

# ПЕРЕМЕННЫЕ СРЕДЫ
ES_REGION: str = os.environ['ES_REGION']
GIT_CREDS_ARN: str = os.environ['GIT_CREDS_ARN']

logger = logging.getLogger()
logger.setLevel(logging.INFO)

# Константы
GIT_ORG: str = 'some-org'
GIT_REPO = 'some-repo'
GIT_ENDPOINT = 'some-end-point'

def get_token():
    session = boto3.session.Session()
    client = session.client(
        service_name="secretsmanager",
        region_name=ES_REGION
    )
    get_secret_value_response = client.get_secret_value(
        SecretId=GIT_CREDS_ARN
    )
    return get_secret_value_response['SecretString']

git_token = get_token()

class GitCommons:

    def read_template_from_git(self, template_path, git_branch):
        git = Github(base_url=GIT_ENDPOINT, login_or_token=git_token)
        org = git.get_organization(GIT_ORG)
        repo = org.get_repo(GIT_REPO)
        contents = repo.get_contents(template_path, ref=git_branch)
        return json.loads(contents.decoded_content.decode())

Я пробовал нижеуказанные реализации юнит-тестов с надеждой, что они пройдут

Ниже приведены тестовые фикстуры и функции из git_commons_2_test.py

@pytest.fixture(scope="session")
def env_var():
    os.environ["ES_REGION"] = "us-east-1"
    os.environ["GIT_CREDS_ARN"] = "12121"
    os.environ["GIT_ORG"] = 'some-org'
    os.environ["GIT_REPO"] = 'some-repo'
    os.environ['GIT_ENDPOINT'] = 'https://dummy'


@pytest.fixture(scope="session")
@mock.patch("boto3.session.Session")
def secrt(mock_session_class, env_var):
    mock_session_object = mock.Mock()
    mock_client = mock.Mock()
    mock_client.get_secret_value.return_value = {'SecretString': 12121212}
    mock_session_object.client.return_value = mock_client
    mock_session_class.return_value = mock_session_object
    from src.search_utils import git_commons
    return git_commons.get_token()


@pytest.fixture()
@mock.patch("github.MainClass.Github")
def github(mock_github_class, secrt, env_var):
    mock_github = mock.Mock()
    mock_org = mock.Mock()
    mock_repo = mock.Mock()
    mock_repo.get_contents.return_value = {"something":"something"}
    mock_org.get_repo.return_value = mock_repo
    mock_github.get_organization.return_value = mock_org
    mock_github_class.return_value = mock_github
    yield mock_github_class

def test_read_template_from_git(github, secrt,env_var ):
    from src.search_utils.git_commons import GitCommons
    template = GitCommons.read_template_from_git(None, "temp", "test")
    print(template)

Я получаю следующую ошибку при выполнении вышеуказанного теста

platform darwin — Python 3.12.6, pytest-8.3.3, pluggy-1.5.0 — /Library/Frameworks/Python.framework/Versions/3.12/bin/python3.12
cachedir: .pytest_cache

__________________________________________________________________________________________________________________________________________________________________________________________________ test_read_template_from_git __________________________________________________________________________________________________________________________________________________________________________________________________

github = <generator object github at 0x106691540>, secrt = 12121212, env_var = None

def test_read_template_from_git(github, secrt,env_var )
    from src.search_utils.git_commons import GitCommons
  template = GitCommons.read_template_from_git(None, "temp", "test")

tests/search_utils/git_commons_2_test.py:51:


src/search_utils/git_commons.py:36: in read_template_from_git
git = Github(base_url=GIT_ENDPOINT, login_or_token=git_token)


self = <github.MainClass.Github object at 0x1071bb560>, login_or_token = 12121212, password = None, jwt = None, app_auth = None, base_url=”https://github.com/api/v3″ (Поскольку объект mock неэффективен, создается новый объект с фактическими значениями), timeout = 15, user_agent=”PyGithub/Python”, per_page = 30, verify = True, retry = GithubRetry(total=10, connect=None, read=None, redirect=None, status=None), pool_size = None, seconds_between_requests = 0.25, seconds_between_writes = 1.0
auth = None

  assert login_or_token is None or isinstance(login_or_token, str), login_or_token

E AssertionError: 12121212

/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/github/MainClass.py:204: AssertionError
——————————————————————————————————————————————————————————————————- Захваченные вызовы логов ——————————————————————————————————————————————————————————————————-
INFO root:git_commons.py:35 прочитал шаблон из git
==================================================================================================================================================================================================== Краткое резюме теста ====================================================================================================================================================================================================
FAILED tests/search_utils/git_commons_2_test.py::test_read_template_from_git – AssertionError: 12121212

Ответ или решение

Ваша проблема связана с тем, что мок-объект для класса Github не используется в методе read_template_from_git, так как git_token инициализируется до того, как тестовая фикция github будет применена. Когда вы вызываете get_token, это происходит в верхнем уровне модуля, а не внутри вашего теста, и поэтому используется реальный клиент AWS и реальный токен.

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

  1. Перенести получение токена в метод класса. Вместо того, чтобы инициализировать git_token на уровне модуля, сделайте это в конструкторе класса GitCommons. Это позволит вам подменять этот токен в тестах.

  2. Передавать токен в конструктор. Это дает вам возможность передать его из теста.

  3. Обновить тестовые фикции. Убедитесь, что мок-объекты работают должным образом и что вы передаете все необходимые зависимости.

Вот как это может выглядеть:

# git_commons.py
import json
from github import Github
import logging
import boto3
import os

# ENV VARIABLES
ES_REGION: str = os.environ['ES_REGION']
GIT_CREDS_ARN: str = os.environ['GIT_CREDS_ARN']

logger = logging.getLogger()
logger.setLevel(logging.INFO)

# Constants
GIT_ORG: str = 'some-org'
GIT_REPO = 'some-repo'
GIT_ENDPOINT = 'some-end-point'

def get_token():
    session = boto3.session.Session()
    client = session.client(
        service_name="secretsmanager",
        region_name=ES_REGION
    )
    get_secret_value_response = client.get_secret_value(
        SecretId=GIT_CREDS_ARN
    )
    return get_secret_value_response['SecretString']

class GitCommons:
    def __init__(self, token):
        self.git = Github(base_url=GIT_ENDPOINT, login_or_token=token)

    def read_template_from_git(self, template_path, git_branch):
        org = self.git.get_organization(GIT_ORG)
        repo = org.get_repo(GIT_REPO)
        contents = repo.get_contents(template_path, ref=git_branch)
        return json.loads(contents.decoded_content.decode())

Теперь в тесте вам нужно будет передать токен при создании экземпляра GitCommons:

# git_commons_2_test.py
import os
import json
from unittest import mock
import pytest

@pytest.fixture(scope="session")
def env_var():
    os.environ["ES_REGION"] = "us-east-1"
    os.environ["GIT_CREDS_ARN"] = "12121"
    os.environ["GIT_ORG"] = "some-org"
    os.environ["GIT_REPO"] = "some-repo"
    os.environ['GIT_ENDPOINT'] = 'https://dummy'

@pytest.fixture(scope="session")
@mock.patch("boto3.session.Session")
def secrt(mock_session_class, env_var):
    mock_session_object = mock.Mock()
    mock_client = mock.Mock()
    mock_client.get_secret_value.return_value = {'SecretString': '12121212'}
    mock_session_object.client.return_value = mock_client
    mock_session_class.return_value = mock_session_object
    from src.search_utils import git_commons
    return git_commons.get_token()

@pytest.fixture()
@mock.patch("github.MainClass.Github")
def github(mock_github_class, secrt, env_var):
    mock_github = mock.Mock()
    mock_org = mock.Mock()
    mock_repo = mock.Mock()
    mock_repo.get_contents.return_value = mock.Mock(decoded_content=json.dumps({"something": "something"}))
    mock_org.get_repo.return_value = mock_repo
    mock_github.get_organization.return_value = mock_org
    mock_github_class.return_value = mock_github
    yield mock_github_class

def test_read_template_from_git(github, secrt, env_var):
    from src.search_utils.git_commons import GitCommons
    git_commons = GitCommons(secrt)
    template = git_commons.read_template_from_git("path/to/template.json", "temp")
    print(template)

В этом коде мы:

  • Переносим логику получения токена в конструктор класса GitCommons.
  • Передаем токен при создании экземпляра GitCommons в тесте.
  • Обеспечиваем, чтобы мок-объекты использовались должным образом.

Теперь ваш тест должен работать без ошибок, и мок-объект для Github будет правильно использован в методе read_template_from_git.

Оцените материал
Добавить комментарий

Капча загружается...