Working factories

This commit is contained in:
Eden Kirin
2023-09-20 21:25:05 +02:00
parent 6109630ed1
commit 6ccb660ccc
8 changed files with 109 additions and 27 deletions

43
poetry.lock generated
View File

@ -31,6 +31,23 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"]
test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
trio = ["trio (>=0.22)"] trio = ["trio (>=0.22)"]
[[package]]
name = "async-factory-boy"
version = "1.0.1"
description = "factory_boy extension with asynchronous ORM support"
optional = false
python-versions = ">=3.7"
files = [
{file = "async_factory_boy-1.0.1-py2.py3-none-any.whl", hash = "sha256:a0a652776ee164b60a45be06aca44a18781710447de1c534dda82d6cfe23f026"},
{file = "async_factory_boy-1.0.1.tar.gz", hash = "sha256:af3a42d9c26b86cc427faf5159ac2e8541b5564bf30424282eb866620af4e143"},
]
[package.dependencies]
factory-boy = ">=3.0.0"
[package.extras]
dev = ["SQLAlchemy", "coverage", "flake8", "isort", "tortoise-orm (>=0.18.1)", "tox", "wheel (>=0.32.0)", "zest.releaser[recommended]"]
[[package]] [[package]]
name = "asyncpg" name = "asyncpg"
version = "0.28.0" version = "0.28.0"
@ -120,15 +137,33 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
] ]
[[package]]
name = "factory-boy"
version = "3.3.0"
description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby."
optional = false
python-versions = ">=3.7"
files = [
{file = "factory_boy-3.3.0-py2.py3-none-any.whl", hash = "sha256:a2cdbdb63228177aa4f1c52f4b6d83fab2b8623bf602c7dedd7eb83c0f69c04c"},
{file = "factory_boy-3.3.0.tar.gz", hash = "sha256:bc76d97d1a65bbd9842a6d722882098eb549ec8ee1081f9fb2e8ff29f0c300f1"},
]
[package.dependencies]
Faker = ">=0.7.0"
[package.extras]
dev = ["Django", "Pillow", "SQLAlchemy", "coverage", "flake8", "isort", "mongoengine", "sqlalchemy-utils", "tox", "wheel (>=0.32.0)", "zest.releaser[recommended]"]
doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"]
[[package]] [[package]]
name = "faker" name = "faker"
version = "19.6.1" version = "19.6.2"
description = "Faker is a Python package that generates fake data for you." description = "Faker is a Python package that generates fake data for you."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "Faker-19.6.1-py3-none-any.whl", hash = "sha256:64c8513c53c3a809075ee527b323a0ba61517814123f3137e4912f5d43350139"}, {file = "Faker-19.6.2-py3-none-any.whl", hash = "sha256:8fba91068dc26e3159c1ac9f22444a2338704b0991d86605322e454bda420092"},
{file = "Faker-19.6.1.tar.gz", hash = "sha256:5d6b7880b3bea708075ddf91938424453f07053a59f8fa0453c1870df6ff3292"}, {file = "Faker-19.6.2.tar.gz", hash = "sha256:d5d5953556b0fb428a46019e03fc2d40eab2980135ddef5a9eb3d054947fdf83"},
] ]
[package.dependencies] [package.dependencies]
@ -974,4 +1009,4 @@ anyio = ">=3.0.0"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "2f47c374edfb8ee537dd4eeb7406bd443bdf0ed3bdd760e764a363ffd1b4650f" content-hash = "553608e41acc31171494d556b327cd6a0f0b5f78846a9a888485f53baa46bee4"

View File

@ -19,6 +19,9 @@ pydantic-settings = "^2.0.3"
pytest = "^7.4.2" pytest = "^7.4.2"
watchfiles = "^0.20.0" watchfiles = "^0.20.0"
pytest-asyncio = "^0.21.1" pytest-asyncio = "^0.21.1"
async-factory-boy = "^1.0.1"
factory-boy = "^3.3.0"
faker = "^19.6.2"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]

View File

View File

View File

@ -0,0 +1,15 @@
import factory
from faker import Faker
from app.domain.city import City
from tests.factories.factory_base import FactoryBase
fake = Faker()
class CityFactory(FactoryBase):
name = factory.Faker("city")
postal_code = factory.Faker("postcode")
class Meta:
model = City

View File

@ -0,0 +1,11 @@
from async_factory_boy.factory.sqlalchemy import AsyncSQLAlchemyFactory
from sqlalchemy.orm import scoped_session
from tests.conftest import async_session_factory
session = scoped_session(async_session_factory)
class FactoryBase(AsyncSQLAlchemyFactory):
class Meta:
sqlalchemy_session = session

28
tests/test_cities.py Normal file
View File

@ -0,0 +1,28 @@
import pytest
from litestar.status_codes import HTTP_200_OK
from litestar.testing import AsyncTestClient
from sqlalchemy.ext.asyncio import AsyncSession
from main import app
from tests.factories.city_factory import CityFactory
class TestCitiesEndpoints:
@pytest.fixture(scope="function", autouse=True)
def setup_class(self, db_session: AsyncSession):
self.db_session = db_session
@pytest.mark.asyncio
async def test_get(self):
city_1 = await CityFactory.create()
city_2 = await CityFactory.create()
city_3 = await CityFactory.create()
city_4 = await CityFactory.create()
city_5 = await CityFactory.create()
async with AsyncTestClient(app=app) as client:
response = await client.get("/v1/cities")
print("#" * 100)
print(response.content)
print("#" * 100)
assert response.status_code == HTTP_200_OK

View File

@ -2,35 +2,25 @@
# https://coderpad.io/blog/development/a-guide-to-database-unit-testing-with-pytest-and-sqlalchemy/ # https://coderpad.io/blog/development/a-guide-to-database-unit-testing-with-pytest-and-sqlalchemy/
import pytest import pytest
from sqlalchemy import text, event from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from sqlalchemy.ext.asyncio import AsyncSession
from app.domain.city import City from tests.factories.city_factory import CityFactory
from app.lib import settings
from app.lib.sqlalchemy_plugin import engine
import pytest
import pytest_asyncio
import sqlalchemy
from sqlalchemy.ext.asyncio import (
AsyncSession,
create_async_engine,
async_scoped_session,
AsyncConnection,
)
class TestGeneral: class TestGeneral:
@pytest.fixture(scope="function", autouse=True) @pytest.fixture(scope="function", autouse=True)
def setup_class(self, db_session): def setup_class(self, db_session: AsyncSession):
self.db_session = db_session self.db_session = db_session
# async def teardown_class(self):
# await self.session.rollback()
# await self.session.close()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_bla(self): async def test_get_cities(self):
city_1 = await CityFactory.create()
city_2 = await CityFactory.create()
city_3 = await CityFactory.create()
city_4 = await CityFactory.create()
city_5 = await CityFactory.create()
stmt = text("select * from cities") stmt = text("select * from cities")
result = await self.db_session.execute(stmt) result = await self.db_session.execute(stmt)
print("#" * 100) print("#" * 100)