Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ isort
pytest
pytest-cov
pytest-mock
testcontainers[postgres]
94 changes: 83 additions & 11 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,94 @@
import importlib
import sys
import uuid
from functools import lru_cache
from pathlib import Path

import pytest
from _pytest.monkeypatch import MonkeyPatch
from alembic import command
from alembic.config import Config as AlembicConfig
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.orm import sessionmaker
from testcontainers.postgres import PostgresContainer

from rating_api.models.db import *
from rating_api.routes import app
from rating_api.settings import Settings
from rating_api.settings import Settings, get_settings


class PostgresConfig:
"""Дата-класс со значениями для контейнера с тестовой БД и alembic-миграции."""

container_name: str = 'rating_test'
username: str = 'postgres'
host: str = 'localhost'
image: str = 'postgres:15'
external_port: int = 5433
ham: str = 'trust'
alembic_ini: str = Path(__file__).resolve().parent.parent / 'alembic.ini'

@classmethod
def get_url(cls):
"""Возвращает URI для подключения к БД."""
return f'postgresql://{cls.username}@{cls.host}:{cls.external_port}/postgres'


@pytest.fixture(scope="session")
def session_mp():
"""Аналог monkeypatch, но с session-scope."""
mp = MonkeyPatch()
yield mp
mp.undo()


@pytest.fixture(scope='session')
def get_settings_mock(session_mp):
"""Переопределение get_settings в rating_api/settings.py и перезагрузка base.app."""

@lru_cache
def get_test_settings() -> Settings:
settings = Settings()
settings.DB_DSN = PostgresConfig.get_url()
return settings

get_settings.cache_clear()
dsn_mock = session_mp.setattr('rating_api.settings.get_settings', get_test_settings)
reloaded_module = sys.modules['rating_api.routes.base']
importlib.reload(reloaded_module)
importlib.reload(sys.modules['rating_api.routes.exc_handlers'])
globals()['app'] = reloaded_module.app
return dsn_mock


@pytest.fixture(scope="session")
def db_container(get_settings_mock):
"""Фикстура настройки БД для тестов в Docker-контейнере."""
container = (
PostgresContainer(
image=PostgresConfig.image, username=PostgresConfig.username, dbname=PostgresConfig.container_name
)
.with_bind_ports(5432, PostgresConfig.external_port)
.with_env("POSTGRES_HOST_AUTH_METHOD", PostgresConfig.ham)
)
container.start()
cfg = AlembicConfig(str(PostgresConfig.alembic_ini.resolve()))
cfg.set_main_option("script_location", "%(here)s/migrations")
command.upgrade(cfg, "head")
try:
yield PostgresConfig.get_url()
finally:
container.stop()


@pytest.fixture()
def dbsession(db_container):
"""Фикстура настройки Session для работы с БД в тестах."""
engine = create_engine(str(db_container), pool_pre_ping=True)
TestingSessionLocal = sessionmaker(bind=engine)
session = TestingSessionLocal()
yield session


@pytest.fixture
Expand All @@ -25,15 +106,6 @@ def client(mocker):
return client


@pytest.fixture
def dbsession() -> Session:
settings = Settings()
engine = create_engine(str(settings.DB_DSN), pool_pre_ping=True)
TestingSessionLocal = sessionmaker(bind=engine)
session = TestingSessionLocal()
yield session


@pytest.fixture
def lecturer(dbsession):
_lecturer = Lecturer(first_name="test_fname", last_name="test_lname", middle_name="test_mname", timetable_id=9900)
Expand Down