From 4155d9f8a6baa92af74d865c6b99d7a4c0a9e5b8 Mon Sep 17 00:00:00 2001 From: Felipe Cardoso Date: Fri, 28 Feb 2025 12:31:47 +0100 Subject: [PATCH] Add comprehensive test cases for User model This commit introduces multiple test cases for the User model, covering creation, updating, deletion, unique constraints, required fields, default values, string representation, and handling of complex JSON preferences. These tests help ensure the model behaves as --- backend/tests/models/test_user.py | 247 +++++++++++++++++++++++++++++- 1 file changed, 246 insertions(+), 1 deletion(-) diff --git a/backend/tests/models/test_user.py b/backend/tests/models/test_user.py index f988e08..bf3077f 100644 --- a/backend/tests/models/test_user.py +++ b/backend/tests/models/test_user.py @@ -1,8 +1,13 @@ # 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( @@ -26,4 +31,244 @@ def test_create_user(db_session): assert created_user is not None assert created_user.email == "test@example.com" assert created_user.first_name == "Test" - assert created_user.preferences == {"theme": "dark"} \ No newline at end of file + 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() + + # Missing first_name + user_no_firstname = User( + id=uuid.uuid4(), + email="nofirstname@example.com", + password_hash="hashedpassword", + # first_name is missing + last_name="User", + ) + db_session.add(user_no_firstname) + with pytest.raises(IntegrityError): + db_session.commit() + db_session.rollback() + + # Missing last_name + user_no_lastname = User( + id=uuid.uuid4(), + email="nolastname@example.com", + password_hash="hashedpassword", + first_name="Test", + # last_name is missing + ) + db_session.add(user_no_lastname) + 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) == "" + assert repr(user) == "" + + +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"] \ No newline at end of file