-
Notifications
You must be signed in to change notification settings - Fork 109
Add tests for registration #66
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,4 +11,5 @@ | |
'plugins.django_settings', | ||
|
||
# TODO: add your own plugins here! | ||
'plugins.identity.user', | ||
] |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,71 @@ | ||||||
from datetime import datetime | ||||||
from typing import Callable, Protocol, TypeAlias, TypedDict, Unpack, final | ||||||
|
||||||
import pytest | ||||||
from mimesis.locales import Locale | ||||||
from mimesis.schema import Field, Schema | ||||||
|
||||||
from server.apps.identity.models import User | ||||||
|
||||||
|
||||||
class UserData(TypedDict, total=False): | ||||||
email: str | ||||||
first_name: str | ||||||
last_name: str | ||||||
date_of_birth: datetime | ||||||
address: str | ||||||
job_title: str | ||||||
phone: str | ||||||
phone_type: int | ||||||
|
||||||
|
||||||
UserAssertion: TypeAlias = Callable[[str, UserData], None] | ||||||
|
||||||
|
||||||
@final | ||||||
class RegistrationData(UserData, total=False): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Remove By default, all attributes are required. Isn't this the case with
Suggested change
|
||||||
password1: str | ||||||
password2: str | ||||||
|
||||||
|
||||||
@final | ||||||
class RegistrationDataFactory(Protocol): # type: ignore[misc] | ||||||
def __call__(self, **fields: Unpack[RegistrationData]) -> RegistrationData: | ||||||
"""User registration data factory.""" | ||||||
|
||||||
|
||||||
@pytest.fixture(scope="session") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. polish: Please use either single or double quotes consistently. Linters typically flag such inconsistencies. I noticed you used single quotes below. Plugins can assist with this, and you can even set up auto-formatting on save to automate this. There are many minor improvements in the code quality that can be made automatically using linters at no extra cost.
Suggested change
|
||||||
def assert_correct_user() -> UserAssertion: | ||||||
def factory(email: str, expected: UserData) -> None: | ||||||
user = User.objects.get(email=email) | ||||||
assert user.id | ||||||
assert user.is_active | ||||||
assert not user.is_superuser | ||||||
assert not user.is_staff | ||||||
for field_name, data_value in expected.items(): | ||||||
assert getattr(user, field_name) == data_value | ||||||
|
||||||
return factory | ||||||
|
||||||
|
||||||
@pytest.fixture(scope='function') | ||||||
def registration_data_factory(faker_seed: int) -> RegistrationDataFactory: | ||||||
def factory(**fields: Unpack[RegistrationData]) -> RegistrationData: | ||||||
mf = Field(locale=Locale.RU, seed=faker_seed) | ||||||
password = mf('password') | ||||||
schema = Schema(schema=lambda: { | ||||||
'email': mf('person.email'), | ||||||
'first_name': mf('person.first_name'), | ||||||
'last_name': mf('person.last_name'), | ||||||
'date_of_birth': mf('datetime.date'), | ||||||
'job_title': mf('person.occupation'), | ||||||
'phone': mf('person.telephone'), | ||||||
'phone_type': mf('choice', items=[1, 2, 3]), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А это поле было в лекции, но в проекте такого поля у User'а нет. Вроде в assert_correct_user должны споткнуться об это, но если тесты проходят - стоит обратить внимание на это |
||||||
}, iterations=1) | ||||||
return { | ||||||
**next(schema), # type: ignore[typeddict-item] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. praise: Using Does it work fine? =) |
||||||
**{'password1': password, 'password2': password}, | ||||||
**fields | ||||||
} | ||||||
|
||||||
return factory |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from typing import TYPE_CHECKING | ||
|
||
import pytest | ||
|
||
if TYPE_CHECKING: | ||
from tests.plugins.identity.user import ( | ||
RegistrationData, | ||
RegistrationDataFactory, | ||
UserData, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def valid_registration_data( | ||
registration_data_factory: 'RegistrationDataFactory' | ||
) -> 'RegistrationData': | ||
return registration_data_factory() | ||
|
||
|
||
@pytest.fixture() | ||
def valid_user_data(valid_registration_data: 'RegistrationData') -> 'UserData': | ||
return { # type: ignore[return-value] | ||
key_name: value_part | ||
for key_name, value_part in valid_registration_data.items() | ||
if not key_name.startswith('password') | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from http import HTTPStatus | ||
from typing import TYPE_CHECKING | ||
|
||
import pytest | ||
from django.test import Client | ||
from django.urls import reverse | ||
|
||
from server.apps.identity.models import User | ||
|
||
if TYPE_CHECKING: | ||
from tests.plugins.identity.user import ( | ||
RegistrationData, | ||
RegistrationDataFactory, | ||
UserAssertion, | ||
UserData, | ||
) | ||
|
||
|
||
def test_registration_page_exists(client: Client) -> None: | ||
response = client.get(reverse('identity:registration')) | ||
assert response.status_code == HTTPStatus.OK | ||
|
||
|
||
@pytest.mark.django_db() | ||
def test_registration_success( | ||
client: Client, | ||
valid_registration_data: 'RegistrationData', | ||
valid_user_data: 'UserData', | ||
assert_correct_user: 'UserAssertion', | ||
) -> None: | ||
"""Test that registration is successfully with valid registration data.""" | ||
response = client.post( | ||
reverse('identity:registration'), | ||
data=valid_registration_data | ||
) | ||
|
||
assert response.status_code == HTTPStatus.OK | ||
assert_correct_user(valid_registration_data['email'], valid_user_data) | ||
|
||
|
||
@pytest.mark.django_db() | ||
@pytest.mark.parametrize('field', User.REQUIRED_FIELDS + [User.USERNAME_FIELD]) | ||
def test_registration_missing_required_field( | ||
client: Client, | ||
registration_data_factory: 'RegistrationDataFactory', | ||
field: str, | ||
) -> None: | ||
post_data = registration_data_factory( | ||
**{field: ''}, # type: ignore[arg-type] | ||
) | ||
|
||
response = client.post( | ||
reverse('identity:registration'), | ||
data=post_data, | ||
) | ||
assert response.status_code == HTTPStatus.OK | ||
assert not User.objects.filter(email=post_data['email']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: If you're using VSCode, there's a plugin called 'Code Spell Checker'.
It's useful for catching typos, though it can produce false errors with variable names.