Add a CRUD Repo test helper to handle basic crud repo testing

This commit is contained in:
Campbell Alden 2026-09-04 00:08:01 +09:00
parent da40febc7f
commit 0d884e5836
2 changed files with 85 additions and 21 deletions

56
src/infra/db_tests.py Normal file
View file

@ -0,0 +1,56 @@
from sqlalchemy import Engine
from typing import Callable
from src.infra import CRUDRepo, Base
import pytest
class CRUDRepoHelper[A: Base, B, C]:
@pytest.fixture
def repo(self, db: Engine) -> CRUDRepo[A, B, C]:
import pdb
pdb.set_trace()
raise NotImplementedError()
@pytest.fixture
def dto(self) -> C:
raise NotImplementedError()
@pytest.fixture
def item(self, repo: CRUDRepo[A, B, C], dto: C) -> B:
return repo.create(dto, None)
@pytest.fixture
def transform(self) -> Callable[[B], B]:
raise NotImplementedError
@pytest.fixture
def expected_transformed_value(self, item: B) -> B:
raise NotImplementedError()
def test_create(self, item: B):
assert item is not None
def test_create_returns_none_if_invalid(self, repo: CRUDRepo[A, B, C], dto: C):
def always_invalid(*_args, **_kw):
raise ValueError('test')
with pytest.raises(ValueError):
repo.create(dto, always_invalid)
def test_create_returns_a_value_if_valid(self, repo: CRUDRepo[A, B, C], dto: C):
assert repo.create(dto, lambda _: None) is not None
def test_get_returns_none_when_missing(self, repo: CRUDRepo[A, B, C]):
assert repo.get(42) is None
def test_get_returns_a_value_if_it_exists(self, repo: CRUDRepo[A, B, C], item: B):
assert repo.get(1) == item
def test_update(self, repo: CRUDRepo[A, B, C], transform: Callable[[B], B], item: B, expected_transformed_value: B):
assert repo.update(1, transform) == expected_transformed_value
def test_delete(self, repo: CRUDRepo[A, B, C], item: B):
assert repo.get(1) is not None
repo.delete(1, None)
assert repo.get(1) is None

View file

@ -1,36 +1,44 @@
from typing import Callable
from sqlalchemy import Engine
from src.infra.db_tests import CRUDRepoHelper
from src.utils.secret import SecretBox from src.utils.secret import SecretBox
from src.services.users.data import UserDTO, User from src.services.users.data import UserDTO, User
from src.services.users.repo import UserRepo
from src.infra.users import UserRepoImpl from src.infra.users import UserRepoImpl
import pytest import pytest
@pytest.fixture class TestUserRepoImpl(CRUDRepoHelper):
def repo(db): @pytest.fixture
def repo(self, db: Engine) -> UserRepoImpl:
return UserRepoImpl(db) return UserRepoImpl(db)
@pytest.fixture
def dto(self) -> UserDTO:
return UserDTO('example@example.com', SecretBox('hunter1'))
@pytest.fixture @pytest.fixture
def users(repo: UserRepo): def expected_transformed_value(self, item: User) -> User:
return [ return User(id=item.id, email='example2@example.com', email_confirmed=True, password_hash=item.password_hash)
repo.create(UserDTO('example@example.com', SecretBox('hunter1')), None),
repo.create(UserDTO('example2@example.com', SecretBox('hunter2')), None),
]
@pytest.fixture
def transform(self) -> Callable[[User], User]:
def do_transform(user: User) -> User:
user.email = 'example2@example.com'
user.email_confirmed = True
return user
def test_getting_a_user_by_email(users: list[User], repo: UserRepo): return do_transform
assert repo.get_user_by_email('example@example.com') == users[0]
def test_getting_a_user_by_email(self, repo: UserRepoImpl, item: User):
assert repo.get_user_by_email('example@example.com') == item
assert repo.get_user_by_email('fred@example.com') is None assert repo.get_user_by_email('fred@example.com') is None
def test_authenticating_as_a_user_can_succeed(self, repo: UserRepoImpl, item: User):
assert repo.auth_as_user(UserDTO('example@example.com', SecretBox('hunter1'))) == item
def test_authenticating_as_a_user_can_succeed(users: list[User], repo: UserRepo): def test_authenticating_fails_with_bad_password(self, repo: UserRepoImpl, item: User):
assert repo.auth_as_user(UserDTO('example@example.com', SecretBox('hunter1'))) == users[0]
def test_authenticating_fails_with_bad_password(users: list[User], repo: UserRepo):
assert repo.auth_as_user(UserDTO('example@example.com', SecretBox('something-wrong'))) is None assert repo.auth_as_user(UserDTO('example@example.com', SecretBox('something-wrong'))) is None
def test_authenticating_fails_for_nonexistent_user(self, repo: UserRepoImpl):
def test_authenticating_fails_for_nonexistent_user(users: list[User], repo: UserRepo):
assert repo.auth_as_user(UserDTO('rando@example.com', SecretBox('test123'))) is None assert repo.auth_as_user(UserDTO('rando@example.com', SecretBox('test123'))) is None