Add a CRUD Repo test helper to handle basic crud repo testing
This commit is contained in:
parent
da40febc7f
commit
0d884e5836
2 changed files with 85 additions and 21 deletions
56
src/infra/db_tests.py
Normal file
56
src/infra/db_tests.py
Normal 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
|
||||
|
|
@ -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.services.users.data import UserDTO, User
|
||||
from src.services.users.repo import UserRepo
|
||||
from src.infra.users import UserRepoImpl
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def repo(db):
|
||||
class TestUserRepoImpl(CRUDRepoHelper):
|
||||
@pytest.fixture
|
||||
def repo(self, db: Engine) -> UserRepoImpl:
|
||||
return UserRepoImpl(db)
|
||||
|
||||
@pytest.fixture
|
||||
def dto(self) -> UserDTO:
|
||||
return UserDTO('example@example.com', SecretBox('hunter1'))
|
||||
|
||||
@pytest.fixture
|
||||
def users(repo: UserRepo):
|
||||
return [
|
||||
repo.create(UserDTO('example@example.com', SecretBox('hunter1')), None),
|
||||
repo.create(UserDTO('example2@example.com', SecretBox('hunter2')), None),
|
||||
]
|
||||
@pytest.fixture
|
||||
def expected_transformed_value(self, item: User) -> User:
|
||||
return User(id=item.id, email='example2@example.com', email_confirmed=True, password_hash=item.password_hash)
|
||||
|
||||
@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):
|
||||
assert repo.get_user_by_email('example@example.com') == users[0]
|
||||
return do_transform
|
||||
|
||||
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
|
||||
|
||||
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):
|
||||
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):
|
||||
def test_authenticating_fails_with_bad_password(self, repo: UserRepoImpl, item: User):
|
||||
assert repo.auth_as_user(UserDTO('example@example.com', SecretBox('something-wrong'))) is None
|
||||
|
||||
|
||||
def test_authenticating_fails_for_nonexistent_user(users: list[User], repo: UserRepo):
|
||||
def test_authenticating_fails_for_nonexistent_user(self, repo: UserRepoImpl):
|
||||
assert repo.auth_as_user(UserDTO('rando@example.com', SecretBox('test123'))) is None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue