FIXDOCKER и typehint в тестах
parent
f61cb3a2ee
commit
ead24d9f28
14
Dockerfile
14
Dockerfile
|
@ -1,15 +1,13 @@
|
|||
FROM python:3.10-slim
|
||||
|
||||
RUN mkdir /fastfood
|
||||
|
||||
WORKDIR /fastfood
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN pip install poetry
|
||||
|
||||
RUN poetry config virtualenvs.create false
|
||||
|
||||
RUN poetry install
|
||||
RUN mkdir -p /usr/src/fastfood
|
||||
|
||||
RUN chmod a+x scripts/*.sh
|
||||
WORKDIR /usr/src/fastfood
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN poetry install
|
||||
|
|
|
@ -98,7 +98,11 @@ Fastapi веб приложение реализующее api для общеп
|
|||
где <db_name> и <db_user> соответвтовали POSTGRES_DB и POSTGRES_USER в файле `.env`
|
||||
|
||||
Создайте и запустите образы
|
||||
> `$ docker-compose up -d --build`
|
||||
Запуск FAstAPI приложения
|
||||
> `$ docker-compose -f compose_app.yml up -d`
|
||||
|
||||
Запуск тестов
|
||||
> `$ docker-compose -f compose_test.yml up`
|
||||
|
||||
После успешного запуска образов документация по API будет доступна по адресу <a href="http://localhost:8000/docs">http://localhost:8000</a>
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
db:
|
||||
container_name: pgdb
|
||||
|
||||
image: postgres:15.1-alpine
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
|
||||
ports:
|
||||
- 6432:5432
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
|
||||
app:
|
||||
container_name: fastfood_app
|
||||
|
||||
build:
|
||||
context: .
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
ports:
|
||||
- 8000:8000
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
restart: always
|
||||
|
||||
command: /bin/bash -c 'poetry run python /usr/src/fastfood/manage.py --run-test-server'
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
db:
|
||||
container_name: pgdb_test
|
||||
|
||||
image: postgres:15.1-alpine
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
environment:
|
||||
POSTGRES_DB: "${POSTGRES_DB}_test"
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
|
||||
ports:
|
||||
- 6432:5432
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}_test"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
|
||||
app:
|
||||
container_name: fastfood_app_test
|
||||
|
||||
build:
|
||||
context: .
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
ports:
|
||||
- 8000:8000
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
restart: always
|
||||
|
||||
command: /bin/bash -c 'poetry run pytest -vv'
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
|
||||
db:
|
||||
image: postgres:15.1-alpine
|
||||
env_file:
|
||||
- .env
|
||||
container_name: pgdatabase
|
||||
ports:
|
||||
- 6432:5432
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
volumes:
|
||||
- ./scripts/db_prepare.sql:/docker-entrypoint-initdb.d/db_prepare.sql
|
||||
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
container_name: fastfood_app
|
||||
env_file:
|
||||
- .env
|
||||
command: ["/fastfood/scripts/migrate_and_run.sh"]
|
||||
ports:
|
||||
- 8000:8000
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: always
|
||||
|
||||
tests:
|
||||
build:
|
||||
context: .
|
||||
container_name: tests
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
app:
|
||||
condition: service_started
|
||||
command: ["/fastfood/scripts/testing.sh"]
|
|
@ -1,5 +1,5 @@
|
|||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
POSTGRES_USER=postges
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_USER=testuser
|
||||
POSTGRES_PASSWORD=test
|
||||
POSTGRES_DB=fastfood_db
|
|
@ -4,9 +4,10 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
|
|||
class Settings(BaseSettings):
|
||||
DB_HOST: str = "db"
|
||||
DB_PORT: int = 5432
|
||||
POSTGRES_DB: str = "fastfod_db"
|
||||
POSTGRES_PASSWORD: str = "postgres"
|
||||
POSTGRES_USER: str = "postgres"
|
||||
POSTGRES_DB: str = "fastfood_db"
|
||||
POSTGRES_PASSWORD: str = "test"
|
||||
POSTGRES_USER: str = "testuser"
|
||||
POSTGRES_DB_TEST: str = "fastfood_db_test"
|
||||
|
||||
@property
|
||||
def DATABASE_URL_asyncpg(self):
|
||||
|
@ -27,7 +28,7 @@ class Settings(BaseSettings):
|
|||
return (
|
||||
"postgresql+asyncpg://"
|
||||
f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
|
||||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}_test"
|
||||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB_TEST}"
|
||||
)
|
||||
|
||||
model_config = SettingsConfigDict(env_file=".env")
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
CREATE DATABASE fastfood_db_test WITH OWNER postgres;
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Тут можно выполнить миграции или дополнительные перед запуском приложения
|
||||
#
|
||||
poetry run python manage.py --run-test-server
|
|
@ -1,2 +0,0 @@
|
|||
#!/bin/bash
|
||||
poetry run pytest -vv
|
|
@ -21,7 +21,7 @@ async_session_maker = async_sessionmaker(
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def event_loop():
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
|
@ -32,7 +32,7 @@ def event_loop():
|
|||
|
||||
|
||||
@pytest_asyncio.fixture(scope="function", autouse=True)
|
||||
async def db_init():
|
||||
async def db_init(event_loop):
|
||||
async with async_engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.drop_all)
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
@ -47,7 +47,7 @@ async def get_test_session() -> AsyncGenerator[AsyncSession, None]:
|
|||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def app() -> Generator[FastAPI, None, None]:
|
||||
def app(event_loop) -> Generator[FastAPI, None, None]:
|
||||
app: FastAPI = create_app()
|
||||
app.dependency_overrides[get_async_session] = get_test_session
|
||||
yield app
|
||||
|
@ -63,6 +63,6 @@ async def client(app) -> AsyncGenerator[AsyncClient, None]:
|
|||
|
||||
|
||||
@pytest_asyncio.fixture(scope="function")
|
||||
async def asession() -> AsyncGenerator[AsyncSession, None]:
|
||||
async def asession(event_loop) -> AsyncGenerator[AsyncSession, None]:
|
||||
async with async_session_maker() as session:
|
||||
yield session
|
||||
|
|
|
@ -47,7 +47,11 @@ class TestBaseCrud:
|
|||
return response.status_code, response.json()
|
||||
|
||||
@staticmethod
|
||||
async def get(ac: AsyncClient, menu: dict, submenu: dict) -> Tuple[int, dict]:
|
||||
async def get(
|
||||
ac: AsyncClient,
|
||||
menu: dict,
|
||||
submenu: dict,
|
||||
) -> Tuple[int, dict]:
|
||||
"""Получение меню по id"""
|
||||
response: Response = await ac.get(
|
||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}",
|
||||
|
@ -55,7 +59,11 @@ class TestBaseCrud:
|
|||
return response.status_code, response.json()
|
||||
|
||||
@staticmethod
|
||||
async def write(ac: AsyncClient, menu: dict, submenu: dict) -> Tuple[int, dict]:
|
||||
async def write(
|
||||
ac: AsyncClient,
|
||||
menu: dict,
|
||||
submenu: dict,
|
||||
) -> Tuple[int, dict]:
|
||||
"""создания меню"""
|
||||
response: Response = await ac.post(
|
||||
f"/{menu.get('id')}/submenus/",
|
||||
|
|
|
@ -48,7 +48,7 @@ async def test_menu(asession: AsyncSession) -> None:
|
|||
async def test_submenu(asession: AsyncSession) -> None:
|
||||
async with asession:
|
||||
# Создаем меню напрямую
|
||||
menu: Menu = Menu(title="SomeMenu", description="SomeDescription")
|
||||
menu = Menu(title="SomeMenu", description="SomeDescription")
|
||||
asession.add(menu)
|
||||
await asession.commit()
|
||||
await asession.refresh(menu)
|
||||
|
@ -69,14 +69,18 @@ async def test_submenu(asession: AsyncSession) -> None:
|
|||
|
||||
# Проверяем подменю
|
||||
req_submenu = await SubMenuCrud.get_submenu_item(
|
||||
menu_id, submenu.id, asession,
|
||||
menu_id,
|
||||
submenu.id,
|
||||
asession,
|
||||
)
|
||||
assert submenu == req_submenu
|
||||
|
||||
# Обновляем меню
|
||||
submenu.title = "UpdatedSubmenu"
|
||||
req_submenu = await SubMenuCrud.update_submenu_item(
|
||||
submenu_id, menubaseschema.model_validate(submenu), asession,
|
||||
submenu_id,
|
||||
menubaseschema.model_validate(submenu),
|
||||
asession,
|
||||
)
|
||||
assert submenu == req_submenu.scalar_one_or_none()
|
||||
|
||||
|
|
Loading…
Reference in New Issue