Вопрос или проблема
Целью является тестирование модуля 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 и реальный токен.
Чтобы это исправить, вы можете изменить структуру вашего кода, чтобы более эффективно использовать фикции. Вот шаги, которые необходимо выполнить:
-
Перенести получение токена в метод класса. Вместо того, чтобы инициализировать
git_token
на уровне модуля, сделайте это в конструкторе классаGitCommons
. Это позволит вам подменять этот токен в тестах. -
Передавать токен в конструктор. Это дает вам возможность передать его из теста.
-
Обновить тестовые фикции. Убедитесь, что мок-объекты работают должным образом и что вы передаете все необходимые зависимости.
Вот как это может выглядеть:
# 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
.