Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added comprehensive test coverage for Group-related models #1020

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{
"eslint.validate": ["javascript", "typescript", "vue"],
"eslint.useFlatConfig": true,
"typescript.tsdk": "./frontend/node_modules/typescript/lib"
"typescript.tsdk": "./frontend/node_modules/typescript/lib",
"python.testing.pytestArgs": [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you give me a quick explanation of why these lines are needed, @zeus2611? Thank you!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VS Code automatically added these lines while I was working on the tests. It seems they were included as part of the editor's configuration updates. Let me know if you’d like me to investigate further!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove these then :) Can you do another commit to do this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah you already did :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

"backend"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
3 changes: 1 addition & 2 deletions backend/entities/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

from .factories import (
OrganizationFactory,
OrganizationApplicationFactory,
# OrganizationApplicationStatusFactory,
OrganizationEventFactory,
OrganizationMemberFactory,
OrganizationResourceFactory,
Expand All @@ -25,6 +23,7 @@


def test_str_methods() -> None:
"""Test the __str__ methods of the entities."""
organization = OrganizationFactory.create()
# Note: Needs to be updated to reflect the recent changes.
# organization_application = OrganizationApplicationFactory.create()
Expand Down
235 changes: 235 additions & 0 deletions backend/entities/tests/test_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
"""
Testing for the Group model.
"""

# mypy: ignore-errors
from datetime import datetime
from uuid import UUID

import pytest
from django.core.exceptions import ValidationError
from faker import Faker

from authentication.factories import UserFactory
from entities.factories import (
GroupFactory,
OrganizationFactory,
)
from entities.models import Group

pytestmark = pytest.mark.django_db


def test_group_creation() -> None:
"""Test complete group creation with all fields."""
user = UserFactory()
org = OrganizationFactory(created_by=user)
fake = Faker()

group = Group.objects.create(
org_id=org,
created_by=user,
group_name=fake.company(),
name=fake.company(),
tagline=fake.catch_phrase(),
location=fake.city(),
category=fake.word(),
get_involved_url=fake.url(),
terms_checked=True,
)

assert isinstance(group.id, UUID)
assert group.org_id == org
assert group.created_by == user
assert isinstance(group.group_name, str)
assert isinstance(group.creation_date, datetime)
assert group.terms_checked is True


def test_required_fields() -> None:
"""Test that required fields raise validation error when missing."""
user = UserFactory()
org = OrganizationFactory(created_by=user)

# 1. Test missing group_name.
with pytest.raises(ValidationError):
group = Group(
org_id=org,
created_by=user,
name="Test Name",
location="Test Location",
category="Test Category",
)
group.full_clean()

# 2. Test missing location.
with pytest.raises(ValidationError):
group = Group(
org_id=org,
created_by=user,
group_name="Test Group",
name="Test Name",
category="Test Category",
)
group.full_clean()


def test_optional_fields() -> None:
"""Test that optional fields can be blank or null."""
user = UserFactory()
org = OrganizationFactory(created_by=user)

group = Group.objects.create(
org_id=org,
created_by=user,
group_name="Test Group",
name="Test Name",
location="Test Location",
category="Test Category",
)

# Should not raise ValidationError.
group.full_clean()
assert group.tagline == ""
assert group.get_involved_url == ""
assert group.terms_checked is False


def test_field_max_lengths() -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @zeus2611,

I reviewed your changes, and they generally look great! 😃 One suggestion before we merge: please remove the tests related to Django, such as those for max_length or auto_fields.

We don't need these tests because Django’s ORM and model field types are already well-tested by the framework itself. We rely on Django's built-in tests to ensure that things like max_length and auto_fields are functioning correctly. Additionally, during the code review process, we check for the correct usage of these features. If there were any issues, we would catch them at that stage.

By removing these tests, we keep the test suite focused on more application-specific logic, avoiding redundancy.

Thanks!

"""Test that fields have correct max lengths."""
user = UserFactory()
org = OrganizationFactory(created_by=user)
fake = Faker()

group = Group.objects.create(
org_id=org,
created_by=user,
group_name=fake.company(),
name=fake.company(),
tagline=fake.catch_phrase(),
location=fake.city(),
category=fake.word(),
get_involved_url=fake.url(),
terms_checked=True,
)

assert len(group.group_name) <= 100
assert len(group.name) <= 100
assert len(group.tagline) <= 200
assert len(group.location) <= 100
assert len(group.category) <= 100
assert len(group.get_involved_url) <= 200


def test_cascade_delete() -> None:
"""Test that deleting an organization deletes all associated groups."""
user = UserFactory()
org = OrganizationFactory(created_by=user)

GroupFactory(org_id=org, created_by=user)

assert Group.objects.count() == 1
org.delete()
assert Group.objects.count() == 0

org = OrganizationFactory(created_by=user)
GroupFactory(org_id=org, created_by=user)

assert Group.objects.count() == 1
user.delete()
assert Group.objects.count() == 0


def test_url_validations() -> None:
"""Test that get_involved_url field is a valid URL."""
user = UserFactory()
org = OrganizationFactory(created_by=user)
fake = Faker()

# 1. Test invalid URL.
with pytest.raises(ValidationError):
group = Group(
org_id=org,
created_by=user,
group_name=fake.company(),
name=fake.company(),
location=fake.city(),
category=fake.word(),
get_involved_url="not a url",
terms_checked=True,
)
group.full_clean()

# 2. Test valid URL.
group = Group.objects.create(
org_id=org,
created_by=user,
group_name=fake.company(),
name=fake.company(),
location=fake.city(),
category=fake.word(),
get_involved_url=fake.url(),
terms_checked=True,
)

group.full_clean()


def test_auto_fields() -> None:
"""Test that auto fields are set correctly."""
user = UserFactory()
org = OrganizationFactory(created_by=user)
fake = Faker()

group = Group.objects.create(
org_id=org,
created_by=user,
group_name=fake.company(),
name=fake.company(),
location=fake.city(),
category=fake.word(),
get_involved_url=fake.url(),
terms_checked=True,
)

assert group.creation_date is not None
assert isinstance(group.creation_date, datetime)
assert group.id is not None
assert isinstance(group.id, UUID)


def test_multiple_groups_per_org() -> None:
"""Test that multiple groups can be created per organization."""
user = UserFactory()
org = OrganizationFactory(created_by=user)
fake = Faker()

group1 = Group.objects.create(
org_id=org,
created_by=user,
group_name=fake.company(),
name=fake.company(),
location=fake.city(),
category=fake.word(),
get_involved_url=fake.url(),
terms_checked=True,
)

group2 = Group.objects.create(
org_id=org,
created_by=user,
group_name=fake.company(),
name=fake.company(),
location=fake.city(),
category=fake.word(),
get_involved_url=fake.url(),
terms_checked=True,
)

assert Group.objects.count() == 2
assert group1.org_id == org
assert group2.org_id == org

org_groups = Group.objects.filter(org_id=org)
assert group1 in org_groups
assert group2 in org_groups
25 changes: 25 additions & 0 deletions backend/entities/tests/test_group_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Test cases for the GroupEvents entity.
"""

import pytest

from entities.factories import GroupEventFactory, GroupFactory

pytestmark = pytest.mark.django_db


def test_group_event_str() -> None:
"""Test string representation of GroupEvent model."""
group_event = GroupEventFactory.build()
assert str(group_event) == f"{group_event.id}"


def test_multiple_events_per_group() -> None:
"""Test multiple events for a single group."""
group = GroupFactory()
events = [GroupEventFactory(group_id=group) for _ in range(3)]

assert len(events) == 3
for event in events:
assert event.group_id == group
57 changes: 57 additions & 0 deletions backend/entities/tests/test_group_member.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""
Test cases for the GroupMember model.
"""

import pytest

from authentication.factories import UserFactory
from entities.factories import GroupFactory, GroupMemberFactory

pytestmark = pytest.mark.django_db


def test_group_member_str() -> None:
"""Test string representation of GroupMember model."""
group_member = GroupMemberFactory.build()
assert str(group_member) == f"{group_member.id}"


def test_group_member_roles() -> None:
"""Test the different roles a group member can have."""
user = UserFactory()
group = GroupFactory()

# 1. Test owner role.
owner = GroupMemberFactory(
group_id=group, user_id=user, is_owner=True, is_admin=False, is_comms=False
)
assert owner.is_owner is True
assert owner.is_admin is False
assert owner.is_comms is False

# 2. Test admin role.
admin = GroupMemberFactory(
group_id=group, user_id=user, is_owner=False, is_admin=True, is_comms=False
)
assert admin.is_owner is False
assert admin.is_admin is True
assert admin.is_comms is False

# 3. Test comms role.
comms = GroupMemberFactory(
group_id=group, user_id=user, is_owner=False, is_admin=False, is_comms=True
)
assert comms.is_owner is False
assert comms.is_admin is False
assert comms.is_comms is True


def test_multiple_members_per_group() -> None:
"""Test multiple members in a single group."""
group = GroupFactory()
members = [GroupMemberFactory(group_id=group) for _ in range(3)]

assert len(members) == 3

for member in members:
assert member.group_id == group
50 changes: 50 additions & 0 deletions backend/entities/tests/test_group_resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Test cases for GroupResource model.
"""

import pytest

from entities.factories import GroupFactory, GroupResourceFactory
from entities.models import GroupResource

pytestmark = pytest.mark.django_db


def test_group_resource_str() -> None:
"""Test string representation of GroupResource model."""
group_resource = GroupResourceFactory.build()
assert str(group_resource) == f"{group_resource.id}"


def test_group_resource_creation() -> None:
"""Test creating a GroupResource instance."""
group = GroupFactory()
resource = GroupResourceFactory(group_id=group)

assert isinstance(resource, GroupResource)
assert resource.group_id == group


def test_multiple_resources_per_group() -> None:
"""Test multiple resources for a single group."""
group = GroupFactory()
resources = [GroupResourceFactory(group_id=group) for _ in range(3)]

assert len(resources) == 3
for resource in resources:
assert resource.group_id == group


def test_group_resource_deletion() -> None:
"""Test cascade deletion when group is deleted."""
group = GroupFactory()
resource = GroupResourceFactory(group_id=group)

# Store resource ID for later verification.
resource_id = resource.id

# Delete the group.
group.delete()

# Verify resource is also deleted.
assert not GroupResource.objects.filter(id=resource_id).exists()
Loading