Skip to content

Commit 03358a0

Browse files
authored
Merge pull request #141 from profcomff/iss138/setup-tests-db
Iss138/setup tests db
2 parents 40af59b + 1b633db commit 03358a0

File tree

2 files changed

+84
-11
lines changed

2 files changed

+84
-11
lines changed

requirements.dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ isort
55
pytest
66
pytest-cov
77
pytest-mock
8+
testcontainers[postgres]

tests/conftest.py

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,94 @@
1+
import importlib
2+
import sys
13
import uuid
4+
from functools import lru_cache
5+
from pathlib import Path
26

37
import pytest
8+
from _pytest.monkeypatch import MonkeyPatch
9+
from alembic import command
10+
from alembic.config import Config as AlembicConfig
411
from fastapi.testclient import TestClient
512
from sqlalchemy import create_engine
6-
from sqlalchemy.orm import Session, sessionmaker
13+
from sqlalchemy.orm import sessionmaker
14+
from testcontainers.postgres import PostgresContainer
715

816
from rating_api.models.db import *
917
from rating_api.routes import app
10-
from rating_api.settings import Settings
18+
from rating_api.settings import Settings, get_settings
19+
20+
21+
class PostgresConfig:
22+
"""Дата-класс со значениями для контейнера с тестовой БД и alembic-миграции."""
23+
24+
container_name: str = 'rating_test'
25+
username: str = 'postgres'
26+
host: str = 'localhost'
27+
image: str = 'postgres:15'
28+
external_port: int = 5433
29+
ham: str = 'trust'
30+
alembic_ini: str = Path(__file__).resolve().parent.parent / 'alembic.ini'
31+
32+
@classmethod
33+
def get_url(cls):
34+
"""Возвращает URI для подключения к БД."""
35+
return f'postgresql://{cls.username}@{cls.host}:{cls.external_port}/postgres'
36+
37+
38+
@pytest.fixture(scope="session")
39+
def session_mp():
40+
"""Аналог monkeypatch, но с session-scope."""
41+
mp = MonkeyPatch()
42+
yield mp
43+
mp.undo()
44+
45+
46+
@pytest.fixture(scope='session')
47+
def get_settings_mock(session_mp):
48+
"""Переопределение get_settings в rating_api/settings.py и перезагрузка base.app."""
49+
50+
@lru_cache
51+
def get_test_settings() -> Settings:
52+
settings = Settings()
53+
settings.DB_DSN = PostgresConfig.get_url()
54+
return settings
55+
56+
get_settings.cache_clear()
57+
dsn_mock = session_mp.setattr('rating_api.settings.get_settings', get_test_settings)
58+
reloaded_module = sys.modules['rating_api.routes.base']
59+
importlib.reload(reloaded_module)
60+
importlib.reload(sys.modules['rating_api.routes.exc_handlers'])
61+
globals()['app'] = reloaded_module.app
62+
return dsn_mock
63+
64+
65+
@pytest.fixture(scope="session")
66+
def db_container(get_settings_mock):
67+
"""Фикстура настройки БД для тестов в Docker-контейнере."""
68+
container = (
69+
PostgresContainer(
70+
image=PostgresConfig.image, username=PostgresConfig.username, dbname=PostgresConfig.container_name
71+
)
72+
.with_bind_ports(5432, PostgresConfig.external_port)
73+
.with_env("POSTGRES_HOST_AUTH_METHOD", PostgresConfig.ham)
74+
)
75+
container.start()
76+
cfg = AlembicConfig(str(PostgresConfig.alembic_ini.resolve()))
77+
cfg.set_main_option("script_location", "%(here)s/migrations")
78+
command.upgrade(cfg, "head")
79+
try:
80+
yield PostgresConfig.get_url()
81+
finally:
82+
container.stop()
83+
84+
85+
@pytest.fixture()
86+
def dbsession(db_container):
87+
"""Фикстура настройки Session для работы с БД в тестах."""
88+
engine = create_engine(str(db_container), pool_pre_ping=True)
89+
TestingSessionLocal = sessionmaker(bind=engine)
90+
session = TestingSessionLocal()
91+
yield session
1192

1293

1394
@pytest.fixture
@@ -25,15 +106,6 @@ def client(mocker):
25106
return client
26107

27108

28-
@pytest.fixture
29-
def dbsession() -> Session:
30-
settings = Settings()
31-
engine = create_engine(str(settings.DB_DSN), pool_pre_ping=True)
32-
TestingSessionLocal = sessionmaker(bind=engine)
33-
session = TestingSessionLocal()
34-
yield session
35-
36-
37109
@pytest.fixture
38110
def lecturer(dbsession):
39111
_lecturer = Lecturer(first_name="test_fname", last_name="test_lname", middle_name="test_mname", timetable_id=9900)

0 commit comments

Comments
 (0)