From 6ccb660ccc5044972b54b87d4324aac0c7cc85a7 Mon Sep 17 00:00:00 2001 From: Eden Kirin Date: Wed, 20 Sep 2023 21:25:05 +0200 Subject: [PATCH] Working factories --- poetry.lock | 43 ++++++++++++++++++++++++++++++--- pyproject.toml | 3 +++ tests/endpoints/__init__.py | 0 tests/factories/__init__.py | 0 tests/factories/city_factory.py | 15 ++++++++++++ tests/factories/factory_base.py | 11 +++++++++ tests/test_cities.py | 28 +++++++++++++++++++++ tests/test_general.py | 36 ++++++++++----------------- 8 files changed, 109 insertions(+), 27 deletions(-) create mode 100644 tests/endpoints/__init__.py create mode 100644 tests/factories/__init__.py create mode 100644 tests/factories/city_factory.py create mode 100644 tests/factories/factory_base.py create mode 100644 tests/test_cities.py diff --git a/poetry.lock b/poetry.lock index 1649c7f..d51191d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -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)"] 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]] name = "asyncpg" version = "0.28.0" @@ -120,15 +137,33 @@ files = [ {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]] name = "faker" -version = "19.6.1" +version = "19.6.2" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.8" files = [ - {file = "Faker-19.6.1-py3-none-any.whl", hash = "sha256:64c8513c53c3a809075ee527b323a0ba61517814123f3137e4912f5d43350139"}, - {file = "Faker-19.6.1.tar.gz", hash = "sha256:5d6b7880b3bea708075ddf91938424453f07053a59f8fa0453c1870df6ff3292"}, + {file = "Faker-19.6.2-py3-none-any.whl", hash = "sha256:8fba91068dc26e3159c1ac9f22444a2338704b0991d86605322e454bda420092"}, + {file = "Faker-19.6.2.tar.gz", hash = "sha256:d5d5953556b0fb428a46019e03fc2d40eab2980135ddef5a9eb3d054947fdf83"}, ] [package.dependencies] @@ -974,4 +1009,4 @@ anyio = ">=3.0.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "2f47c374edfb8ee537dd4eeb7406bd443bdf0ed3bdd760e764a363ffd1b4650f" +content-hash = "553608e41acc31171494d556b327cd6a0f0b5f78846a9a888485f53baa46bee4" diff --git a/pyproject.toml b/pyproject.toml index 4998ad0..dfc485f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,9 @@ pydantic-settings = "^2.0.3" pytest = "^7.4.2" watchfiles = "^0.20.0" pytest-asyncio = "^0.21.1" +async-factory-boy = "^1.0.1" +factory-boy = "^3.3.0" +faker = "^19.6.2" [build-system] requires = ["poetry-core"] diff --git a/tests/endpoints/__init__.py b/tests/endpoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/factories/__init__.py b/tests/factories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/factories/city_factory.py b/tests/factories/city_factory.py new file mode 100644 index 0000000..eb79445 --- /dev/null +++ b/tests/factories/city_factory.py @@ -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 diff --git a/tests/factories/factory_base.py b/tests/factories/factory_base.py new file mode 100644 index 0000000..d030a8d --- /dev/null +++ b/tests/factories/factory_base.py @@ -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 diff --git a/tests/test_cities.py b/tests/test_cities.py new file mode 100644 index 0000000..5f3e928 --- /dev/null +++ b/tests/test_cities.py @@ -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 diff --git a/tests/test_general.py b/tests/test_general.py index 97c1b4c..a005844 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -2,40 +2,30 @@ # https://coderpad.io/blog/development/a-guide-to-database-unit-testing-with-pytest-and-sqlalchemy/ import pytest -from sqlalchemy import text, event -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker +from sqlalchemy import text +from sqlalchemy.ext.asyncio import AsyncSession -from app.domain.city import City -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, -) +from tests.factories.city_factory import CityFactory class TestGeneral: @pytest.fixture(scope="function", autouse=True) - def setup_class(self, db_session): + def setup_class(self, db_session: AsyncSession): self.db_session = db_session - # async def teardown_class(self): - # await self.session.rollback() - # await self.session.close() - @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") result = await self.db_session.execute(stmt) - print("#"*100) + print("#" * 100) for c in result: print(c) - print("#"*100) + print("#" * 100) assert True