Skip to content

Commit

Permalink
Merge pull request #46 from AndrewSergienko/2.х/tests
Browse files Browse the repository at this point in the history
Add tests
  • Loading branch information
andiserg authored Feb 10, 2024
2 parents 751a10c + 61a2ab9 commit 2c59fa8
Show file tree
Hide file tree
Showing 23 changed files with 269 additions and 49 deletions.
2 changes: 1 addition & 1 deletion src/costy/adapters/db/category_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from sqlalchemy import delete, or_, select
from sqlalchemy.ext.asyncio import AsyncSession

from costy.application.category.read_available_categories import CategoryDTO
from costy.application.category.dto import CategoryDTO
from costy.application.common.category_gateway import (
CategoriesReader,
CategoryDeleter,
Expand Down
5 changes: 1 addition & 4 deletions src/costy/application/category/create_category.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
from ..common.id_provider import IdProvider
from ..common.interactor import Interactor
from ..common.uow import UoW


class NewCategoryDTO:
name: str
from .dto import NewCategoryDTO


class CreateCategory(Interactor[NewCategoryDTO, CategoryId]):
Expand Down
20 changes: 20 additions & 0 deletions src/costy/application/category/dto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from dataclasses import dataclass

from costy.domain.models.category import CategoryId, CategoryType


@dataclass
class NewCategoryDTO:
name: str


@dataclass
class ReadAvailableCategoriesDTO:
...


@dataclass
class CategoryDTO:
id: CategoryId | None
name: str
kind: CategoryType
15 changes: 1 addition & 14 deletions src/costy/application/category/read_available_categories.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
from dataclasses import dataclass
from typing import List, Optional

from costy.domain.models.category import CategoryId, CategoryType
from costy.domain.services.category import CategoryService

from ..common.category_gateway import CategoriesReader
from ..common.id_provider import IdProvider
from ..common.interactor import Interactor
from ..common.uow import UoW


@dataclass
class ReadAvailableCategoriesDTO:
...


@dataclass
class CategoryDTO:
id: CategoryId | None
name: str
kind: CategoryType
from .dto import CategoryDTO, ReadAvailableCategoriesDTO


class ReadAvailableCategories(Interactor[None, List[CategoryDTO]]):
Expand Down
2 changes: 1 addition & 1 deletion src/costy/application/common/category_gateway.py
Original file line number Diff line number Diff line change
@@ -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.dto import CategoryDTO
from costy.domain.models.category import Category, CategoryId
from costy.domain.models.user import UserId

Expand Down
12 changes: 1 addition & 11 deletions src/costy/application/operation/create_operation.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
from dataclasses import dataclass

from costy.application.common.id_provider import IdProvider
from costy.application.common.interactor import Interactor
from costy.application.common.operation_gateway import OperationSaver
from costy.application.common.uow import UoW
from costy.domain.models.category import CategoryId
from costy.application.operation.dto import NewOperationDTO
from costy.domain.models.operation import OperationId
from costy.domain.services.operation import OperationService


@dataclass
class NewOperationDTO:
amount: int
description: str | None
time: int
category_id: CategoryId


class CreateOperation(Interactor[NewOperationDTO, OperationId]):
def __init__(
self,
Expand Down
17 changes: 17 additions & 0 deletions src/costy/application/operation/dto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from dataclasses import dataclass

from costy.domain.models.category import CategoryId


@dataclass
class NewOperationDTO:
amount: int
description: str | None
time: int
category_id: CategoryId


@dataclass
class ListOperationDTO:
from_time: int | None
to_time: int | None
8 changes: 1 addition & 7 deletions src/costy/application/operation/read_list_operation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from dataclasses import dataclass
from typing import List

from costy.domain.models.operation import Operation
Expand All @@ -8,12 +7,7 @@
from ..common.interactor import Interactor
from ..common.operation_gateway import OperationsReader
from ..common.uow import UoW


@dataclass
class ListOperationDTO:
from_time: int | None
to_time: int | None
from .dto import ListOperationDTO


class ReadListOperation(Interactor[ListOperationDTO, List[Operation]]):
Expand Down
9 changes: 1 addition & 8 deletions src/costy/application/user/create_user.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
from dataclasses import dataclass

from costy.domain.models.user import UserId
from costy.domain.services.user import UserService

from ..common.interactor import Interactor
from ..common.uow import UoW
from ..common.user_gateway import UserSaver


@dataclass
class NewUserDTO:
email: str
password: str
from .dto import NewUserDTO


class CreateUser(Interactor[NewUserDTO, UserId]):
Expand Down
7 changes: 7 additions & 0 deletions src/costy/application/user/dto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from dataclasses import dataclass


@dataclass
class NewUserDTO:
email: str
password: str
2 changes: 1 addition & 1 deletion src/costy/domain/models/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
OperationId = NewType("OperationId", int)


@dataclass(kw_only=True)
@dataclass
class Operation:
id: OperationId | None
amount: int
Expand Down
Empty file added tests/application/__init__.py
Empty file.
Empty file.
41 changes: 41 additions & 0 deletions tests/application/category/test_create_category.py
Original file line number Diff line number Diff line change
@@ -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
Empty file.
49 changes: 49 additions & 0 deletions tests/application/operation/test_create_operation.py
Original file line number Diff line number Diff line change
@@ -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
30 changes: 30 additions & 0 deletions tests/application/test_authenticate.py
Original file line number Diff line number Diff line change
@@ -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
Empty file.
38 changes: 38 additions & 0 deletions tests/application/user/test_create_user.py
Original file line number Diff line number Diff line change
@@ -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
30 changes: 30 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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
Empty file added tests/domain/__init__.py
Empty file.
29 changes: 29 additions & 0 deletions tests/domain/test_create.py
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 2c59fa8

Please sign in to comment.