forked from cardosofelipe/fast-next-template
Add comprehensive test suite and utilities for user functionality
This commit introduces a suite of tests for user models, schemas, CRUD operations, and authentication services. It also adds utilities for in-memory database setup to support these tests and updates environment settings for consistency.
This commit is contained in:
0
backend/tests/models/__init__.py
Normal file
0
backend/tests/models/__init__.py
Normal file
249
backend/tests/models/test_user.py
Normal file
249
backend/tests/models/test_user.py
Normal file
@@ -0,0 +1,249 @@
|
||||
# tests/models/test_user.py
|
||||
import uuid
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
def test_create_user(db_session):
|
||||
"""Test creating a basic user."""
|
||||
# Arrange
|
||||
user_id = uuid.uuid4()
|
||||
new_user = User(
|
||||
id=user_id,
|
||||
email="test@example.com",
|
||||
password_hash="hashedpassword",
|
||||
first_name="Test",
|
||||
last_name="User",
|
||||
phone_number="1234567890",
|
||||
is_active=True,
|
||||
is_superuser=False,
|
||||
preferences={"theme": "dark"},
|
||||
)
|
||||
db_session.add(new_user)
|
||||
|
||||
# Act
|
||||
db_session.commit()
|
||||
created_user = db_session.query(User).filter_by(email="test@example.com").first()
|
||||
|
||||
# Assert
|
||||
assert created_user is not None
|
||||
assert created_user.email == "test@example.com"
|
||||
assert created_user.first_name == "Test"
|
||||
assert created_user.last_name == "User"
|
||||
assert created_user.phone_number == "1234567890"
|
||||
assert created_user.is_active is True
|
||||
assert created_user.is_superuser is False
|
||||
assert created_user.preferences == {"theme": "dark"}
|
||||
# UUID should be preserved
|
||||
assert created_user.id == user_id
|
||||
# Timestamps should be set
|
||||
assert isinstance(created_user.created_at, datetime)
|
||||
assert isinstance(created_user.updated_at, datetime)
|
||||
|
||||
|
||||
def test_update_user(db_session):
|
||||
"""Test updating an existing user."""
|
||||
# Arrange - Create a user
|
||||
user_id = uuid.uuid4()
|
||||
user = User(
|
||||
id=user_id,
|
||||
email="update@example.com",
|
||||
password_hash="hashedpassword",
|
||||
first_name="Before",
|
||||
last_name="Update",
|
||||
)
|
||||
db_session.add(user)
|
||||
db_session.commit()
|
||||
|
||||
# Record the original creation timestamp
|
||||
original_created_at = user.created_at
|
||||
|
||||
# Act - Update the user
|
||||
user.first_name = "After"
|
||||
user.last_name = "Updated"
|
||||
user.phone_number = "9876543210"
|
||||
user.preferences = {"theme": "light", "notifications": True}
|
||||
db_session.commit()
|
||||
|
||||
# Fetch the updated user to verify changes were persisted
|
||||
updated_user = db_session.query(User).filter_by(id=user_id).first()
|
||||
|
||||
# Assert
|
||||
assert updated_user.first_name == "After"
|
||||
assert updated_user.last_name == "Updated"
|
||||
assert updated_user.phone_number == "9876543210"
|
||||
assert updated_user.preferences == {"theme": "light", "notifications": True}
|
||||
# created_at shouldn't change on update
|
||||
assert updated_user.created_at == original_created_at
|
||||
# updated_at should be newer than created_at
|
||||
assert updated_user.updated_at > original_created_at
|
||||
|
||||
|
||||
def test_delete_user(db_session):
|
||||
"""Test deleting a user."""
|
||||
# Arrange - Create a user
|
||||
user_id = uuid.uuid4()
|
||||
user = User(
|
||||
id=user_id,
|
||||
email="delete@example.com",
|
||||
password_hash="hashedpassword",
|
||||
first_name="Delete",
|
||||
last_name="Me",
|
||||
)
|
||||
db_session.add(user)
|
||||
db_session.commit()
|
||||
|
||||
# Act - Delete the user
|
||||
db_session.delete(user)
|
||||
db_session.commit()
|
||||
|
||||
# Assert
|
||||
deleted_user = db_session.query(User).filter_by(id=user_id).first()
|
||||
assert deleted_user is None
|
||||
|
||||
|
||||
def test_user_unique_email_constraint(db_session):
|
||||
"""Test that users cannot have duplicate emails."""
|
||||
# Arrange - Create a user
|
||||
user1 = User(
|
||||
id=uuid.uuid4(),
|
||||
email="duplicate@example.com",
|
||||
password_hash="hashedpassword",
|
||||
first_name="First",
|
||||
last_name="User",
|
||||
)
|
||||
db_session.add(user1)
|
||||
db_session.commit()
|
||||
|
||||
# Act & Assert - Try to create another user with the same email
|
||||
user2 = User(
|
||||
id=uuid.uuid4(),
|
||||
email="duplicate@example.com", # Same email
|
||||
password_hash="differenthash",
|
||||
first_name="Second",
|
||||
last_name="User",
|
||||
)
|
||||
db_session.add(user2)
|
||||
|
||||
# Should raise IntegrityError due to unique constraint
|
||||
with pytest.raises(IntegrityError):
|
||||
db_session.commit()
|
||||
|
||||
# Rollback for cleanup
|
||||
db_session.rollback()
|
||||
|
||||
|
||||
def test_user_required_fields(db_session):
|
||||
"""Test that required fields are enforced."""
|
||||
# Test each required field by creating a user without it
|
||||
|
||||
# Missing email
|
||||
user_no_email = User(
|
||||
id=uuid.uuid4(),
|
||||
# email is missing
|
||||
password_hash="hashedpassword",
|
||||
first_name="Test",
|
||||
last_name="User",
|
||||
)
|
||||
db_session.add(user_no_email)
|
||||
with pytest.raises(IntegrityError):
|
||||
db_session.commit()
|
||||
db_session.rollback()
|
||||
|
||||
# Missing password_hash
|
||||
user_no_password = User(
|
||||
id=uuid.uuid4(),
|
||||
email="nopassword@example.com",
|
||||
# password_hash is missing
|
||||
first_name="Test",
|
||||
last_name="User",
|
||||
)
|
||||
db_session.add(user_no_password)
|
||||
with pytest.raises(IntegrityError):
|
||||
db_session.commit()
|
||||
db_session.rollback()
|
||||
|
||||
|
||||
|
||||
def test_user_defaults(db_session):
|
||||
"""Test that default values are correctly set."""
|
||||
# Arrange - Create a minimal user with only required fields
|
||||
minimal_user = User(
|
||||
id=uuid.uuid4(),
|
||||
email="minimal@example.com",
|
||||
password_hash="hashedpassword",
|
||||
first_name="Minimal",
|
||||
last_name="User",
|
||||
)
|
||||
db_session.add(minimal_user)
|
||||
db_session.commit()
|
||||
|
||||
# Act - Retrieve the user
|
||||
created_user = db_session.query(User).filter_by(email="minimal@example.com").first()
|
||||
|
||||
# Assert - Check default values
|
||||
assert created_user.is_active is True # Default should be True
|
||||
assert created_user.is_superuser is False # Default should be False
|
||||
assert created_user.phone_number is None # Optional field
|
||||
assert created_user.preferences is None # Optional field
|
||||
|
||||
|
||||
def test_user_string_representation(db_session):
|
||||
"""Test the string representation of a user."""
|
||||
# Arrange
|
||||
user = User(
|
||||
id=uuid.uuid4(),
|
||||
email="repr@example.com",
|
||||
password_hash="hashedpassword",
|
||||
first_name="String",
|
||||
last_name="Repr",
|
||||
)
|
||||
|
||||
# Act & Assert
|
||||
assert str(user) == "<User repr@example.com>"
|
||||
assert repr(user) == "<User repr@example.com>"
|
||||
|
||||
|
||||
def test_user_with_complex_json_preferences(db_session):
|
||||
"""Test storing and retrieving complex JSON preferences."""
|
||||
# Arrange - Create a user with nested JSON preferences
|
||||
complex_preferences = {
|
||||
"theme": {
|
||||
"mode": "dark",
|
||||
"colors": {
|
||||
"primary": "#333",
|
||||
"secondary": "#666"
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"email": True,
|
||||
"sms": False,
|
||||
"push": {
|
||||
"enabled": True,
|
||||
"quiet_hours": [22, 7]
|
||||
}
|
||||
},
|
||||
"tags": ["important", "family", "events"]
|
||||
}
|
||||
|
||||
user = User(
|
||||
id=uuid.uuid4(),
|
||||
email="complex@example.com",
|
||||
password_hash="hashedpassword",
|
||||
first_name="Complex",
|
||||
last_name="JSON",
|
||||
preferences=complex_preferences
|
||||
)
|
||||
db_session.add(user)
|
||||
db_session.commit()
|
||||
|
||||
# Act - Retrieve the user
|
||||
retrieved_user = db_session.query(User).filter_by(email="complex@example.com").first()
|
||||
|
||||
# Assert - The complex JSON should be preserved
|
||||
assert retrieved_user.preferences == complex_preferences
|
||||
assert retrieved_user.preferences["theme"]["colors"]["primary"] == "#333"
|
||||
assert retrieved_user.preferences["notifications"]["push"]["quiet_hours"] == [22, 7]
|
||||
assert "important" in retrieved_user.preferences["tags"]
|
||||
Reference in New Issue
Block a user