diff --git a/src/costy/application/category/create_category.py b/src/costy/application/category/create_category.py index 38f0c91..961cc9a 100644 --- a/src/costy/application/category/create_category.py +++ b/src/costy/application/category/create_category.py @@ -1,3 +1,5 @@ +from dataclasses import dataclass + from costy.domain.models.category import CategoryId, CategoryType from costy.domain.services.category import CategoryService @@ -7,6 +9,7 @@ from ..common.uow import UoW +@dataclass class NewCategoryDTO: name: str diff --git a/src/costy/application/common/category_gateway.py b/src/costy/application/common/category_gateway.py index a82479f..00b298c 100644 --- a/src/costy/application/common/category_gateway.py +++ b/src/costy/application/common/category_gateway.py @@ -1,7 +1,7 @@ from abc import abstractmethod from typing import Protocol, runtime_checkable -from costy.application.category.read_available_categories import CategoryDTO +# from costy.application.category.read_available_categories import CategoryDTO from costy.domain.models.category import Category, CategoryId from costy.domain.models.user import UserId @@ -23,7 +23,7 @@ async def get_category(self, category_id: CategoryId) -> Category | None: @runtime_checkable class CategoriesReader(Protocol): @abstractmethod - async def find_categories(self, user_id: UserId) -> list[CategoryDTO]: + async def find_categories(self, user_id: UserId) -> list[Category]: raise NotImplementedError diff --git a/src/costy/domain/models/operation.py b/src/costy/domain/models/operation.py index b30a636..4f138bb 100644 --- a/src/costy/domain/models/operation.py +++ b/src/costy/domain/models/operation.py @@ -7,7 +7,7 @@ OperationId = NewType("OperationId", int) -@dataclass(kw_only=True) +@dataclass class Operation: id: OperationId | None amount: int diff --git a/tests/application/__init__.py b/tests/application/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/application/category/__init__.py b/tests/application/category/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/application/category/test_create_category.py b/tests/application/category/test_create_category.py new file mode 100644 index 0000000..ff65235 --- /dev/null +++ b/tests/application/category/test_create_category.py @@ -0,0 +1,41 @@ +from unittest.mock import Mock + +import pytest +from pytest import fixture + +from costy.application.category.create_category import ( + CreateCategory, + NewCategoryDTO, +) +from costy.application.common.category_gateway import CategorySaver +from costy.application.common.uow import UoW +from costy.domain.models.category import Category, CategoryType + + +@fixture +def category_info() -> NewCategoryDTO: + return NewCategoryDTO("test") + + +@fixture +def interactor(id_provider, category_id, user_id, category_info) -> CreateCategory: + category_service = Mock() + category_service.create.return_value = Category( + id=None, + name=category_info.name, + kind=CategoryType.PERSONAL.value, + user_id=user_id, + ) + + async def save_category_mock(category: Category) -> None: + category.id = category_id + + category_gateway = Mock(spec=CategorySaver) + category_gateway.save_category = save_category_mock + uow = Mock(spec=UoW) + return CreateCategory(category_service, category_gateway, id_provider, uow) + + +@pytest.mark.asyncio +async def test_create_operation(interactor: CreateCategory, category_info: NewCategoryDTO, category_id) -> None: + assert await interactor(category_info) == category_id diff --git a/tests/application/operation/__init__.py b/tests/application/operation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/application/operation/test_create_operation.py b/tests/application/operation/test_create_operation.py new file mode 100644 index 0000000..aa33506 --- /dev/null +++ b/tests/application/operation/test_create_operation.py @@ -0,0 +1,49 @@ +from unittest.mock import Mock + +import pytest +from pytest import fixture + +from costy.application.common.operation_gateway import OperationSaver +from costy.application.common.uow import UoW +from costy.application.operation.create_operation import ( + CreateOperation, + NewOperationDTO, +) +from costy.domain.models.category import CategoryId +from costy.domain.models.operation import Operation + + +@fixture +def operation_info() -> NewOperationDTO: + return NewOperationDTO( + 100, + "description", + 10000, + CategoryId(999) + ) + + +@fixture +def interactor(id_provider, operation_id, user_id, operation_info) -> CreateOperation: + operation_service = Mock() + operation_service.create.return_value = Operation( + id=None, + amount=operation_info.amount, + description=operation_info.description, + time=operation_info.time, + user_id=user_id, + category_id=operation_info.category_id, + ) + + async def save_operation_mock(operation: Operation) -> None: + operation.id = operation_id + + operation_gateway = Mock(spec=OperationSaver) + operation_gateway.save_operation = save_operation_mock + uow = Mock(spec=UoW) + return CreateOperation(operation_service, operation_gateway, id_provider, uow) + + +@pytest.mark.asyncio +async def test_create_operation(interactor: CreateOperation, operation_info: NewOperationDTO, operation_id) -> None: + assert await interactor(operation_info) == operation_id diff --git a/tests/application/test_authenticate.py b/tests/application/test_authenticate.py new file mode 100644 index 0000000..3ee43c6 --- /dev/null +++ b/tests/application/test_authenticate.py @@ -0,0 +1,30 @@ +from unittest.mock import Mock + +import pytest +from pytest import fixture + +from costy.application.authenticate import Authenticate, LoginInputDTO +from costy.application.common.uow import UoW +from costy.application.common.user_gateway import UserReader +from costy.domain.models.user import User, UserId + + +@fixture +def login_info() -> LoginInputDTO: + return LoginInputDTO(email="test@email.com", password="password") + + +@fixture +def interactor(user_id, login_info): + user_gateway = Mock(spec=UserReader) + user_gateway.get_user_by_email.return_value = User( + id=user_id, email=login_info.email, + hashed_password=login_info.password, + ) + uow = Mock(spec=UoW) + return Authenticate(user_gateway, uow) + + +@pytest.mark.asyncio +async def test_authenticate(interactor: Authenticate, user_id: UserId, login_info: LoginInputDTO): + assert await interactor(login_info) == user_id diff --git a/tests/application/user/__init__.py b/tests/application/user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/application/user/test_create_user.py b/tests/application/user/test_create_user.py new file mode 100644 index 0000000..3f63aa5 --- /dev/null +++ b/tests/application/user/test_create_user.py @@ -0,0 +1,38 @@ +from unittest.mock import Mock + +import pytest +from pytest import fixture + +from costy.application.common.uow import UoW +from costy.application.common.user_gateway import UserSaver +from costy.application.user.create_user import CreateUser, NewUserDTO +from costy.domain.models.user import User, UserId +from costy.domain.services.user import UserService + + +@fixture +def user_info() -> NewUserDTO: + return NewUserDTO(email="test@email.com", password="password") + + +@fixture +def interactor(user_id, user_info): + user_service = Mock(spec=UserService) + user_service.create.return_value = User( + id=None, + email=user_info.email, + hashed_password=user_info.password + ) + + async def mock_save_user(user: User): + user.id = user_id + + user_gateway = Mock(spec=UserSaver) + user_gateway.save_user = mock_save_user + uow = Mock(spec=UoW) + return CreateUser(user_service, user_gateway, uow) + + +@pytest.mark.asyncio +async def test_create_user(interactor: CreateUser, user_info: NewUserDTO, user_id: UserId): + assert await interactor(user_info) == user_id diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..754af96 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,30 @@ +from unittest.mock import Mock + +from pytest import fixture + +from costy.application.common.id_provider import IdProvider +from costy.domain.models.category import CategoryId +from costy.domain.models.operation import OperationId +from costy.domain.models.user import UserId + + +@fixture +def user_id() -> UserId: + return UserId(999) + + +@fixture +def operation_id() -> OperationId: + return OperationId(999) + + +@fixture +def category_id() -> CategoryId: + return CategoryId(999) + + +@fixture +def id_provider(user_id: UserId) -> IdProvider: + provider = Mock(spec=IdProvider) + provider.get_current_user_id.return_value = user_id + return provider diff --git a/tests/domain/__init__.py b/tests/domain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/domain/test_create.py b/tests/domain/test_create.py new file mode 100644 index 0000000..d7ff151 --- /dev/null +++ b/tests/domain/test_create.py @@ -0,0 +1,29 @@ +import pytest + +from costy.domain.models.category import Category, CategoryId, CategoryType +from costy.domain.models.operation import Operation +from costy.domain.models.user import User, UserId +from costy.domain.services.category import CategoryService +from costy.domain.services.operation import OperationService +from costy.domain.services.user import UserService + + +@pytest.mark.parametrize("domain_service, data, expected_model", [ + ( + UserService(), + ("email@test.com", "password"), + User(None, "email@test.com", "password") + ), + ( + OperationService(), + (100, "desc", 10000, UserId(9999), CategoryId(9999)), + Operation(None, 100, "desc", 10000, UserId(9999), CategoryId(9999)) + ), + ( + CategoryService(), + ("test", CategoryType.GENERAL, UserId(9999)), + Category(None, "test", CategoryType.GENERAL.value, UserId(9999)) + ), +]) +def test_create_domain_service(domain_service, data, expected_model): + assert domain_service.create(*data) == expected_model diff --git a/tests/test_stable.py b/tests/test_stable.py deleted file mode 100644 index 1af438d..0000000 --- a/tests/test_stable.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_stable(): - assert True