Skip to content

Commit 8f71221

Browse files
committed
test: refactor to adopt factories
1 parent 5cf25e1 commit 8f71221

File tree

5 files changed

+68
-112
lines changed

5 files changed

+68
-112
lines changed

chores/tests/factories.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import factory
2+
from django.contrib.auth import get_user_model
3+
4+
User = get_user_model()
5+
6+
7+
class UserFactory(factory.django.DjangoModelFactory):
8+
class Meta:
9+
model = User
10+
11+
email = factory.Faker('email')
12+
first_name = factory.Faker('first_name')
13+
last_name = factory.Faker('last_name')
14+
telegram_user_id = factory.Faker('uuid4')
15+
password = factory.PostGenerationMethodCall('set_password', 'password123')

chores/tests/test_commands.py

Lines changed: 19 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,17 @@
44

55
import time_machine
66
from django.core import mail
7-
from django.core.exceptions import ValidationError
87
from django.core.management import call_command
98
from django.test import TestCase
109

11-
from members.models import User
12-
1310
from ..models import Chore, ChoreNotification, ChoreVolunteer
11+
from .factories import UserFactory
1412

1513

1614
class CustomCommandTest(TestCase):
1715
def setUp(self):
18-
self.user = User.objects.create_user(
16+
self.user = UserFactory(
1917
20-
password="testpass123",
21-
first_name="Task",
22-
last_name="User",
23-
telegram_user_id="987654321",
2418
)
2519

2620
@time_machine.travel("2025-07-10 19:56")
@@ -218,12 +212,8 @@ def test_email_reminding_volunteers(self):
218212
},
219213
creator=self.user,
220214
)
221-
volunteeruser = User.objects.create_user(
215+
volunteeruser = UserFactory(
222216
223-
password="testpass123",
224-
first_name="Task",
225-
last_name="Volunteer",
226-
telegram_user_id="987654322",
227217
)
228218
ChoreVolunteer.objects.create(
229219
user=volunteeruser, chore=chore, timestamp=1753041600
@@ -247,14 +237,10 @@ def test_email_reminding_volunteers(self):
247237
self.assertIn("Volunteering reminder", email.subject)
248238
self.assertIn("friendly reminder that you signed up for", email.body)
249239

240+
250241
class SingleOccurrenceChoreTest(TestCase):
251242
def setUp(self):
252-
self.user = User.objects.create_user(
253-
254-
password="testpass123",
255-
first_name="Test",
256-
last_name="User",
257-
)
243+
self.user = UserFactory()
258244

259245
@time_machine.travel("2025-07-10 19:56")
260246
def test_single_occurrence_chore_reminder(self):
@@ -299,12 +285,7 @@ def test_single_occurrence_chore_reminder(self):
299285

300286
class NoVolunteersNeededTest(TestCase):
301287
def setUp(self):
302-
self.user = User.objects.create_user(
303-
304-
password="testpass123",
305-
first_name="Test",
306-
last_name="User",
307-
)
288+
self.user = UserFactory()
308289

309290
@time_machine.travel("2025-07-10 19:56")
310291
def test_no_reminder_when_volunteers_exist(self):
@@ -342,12 +323,7 @@ def test_no_reminder_when_volunteers_exist(self):
342323
)
343324

344325
# Create a volunteer
345-
volunteer_user = User.objects.create_user(
346-
347-
password="testpass123",
348-
first_name="Volunteer",
349-
last_name="User",
350-
)
326+
volunteer_user = UserFactory()
351327
ChoreVolunteer.objects.create(
352328
user=volunteer_user,
353329
chore=chore,
@@ -364,12 +340,7 @@ def test_no_reminder_when_volunteers_exist(self):
364340

365341
class InvalidChoreTypeTest(TestCase):
366342
def setUp(self):
367-
self.user = User.objects.create_user(
368-
369-
password="testpass123",
370-
first_name="Test",
371-
last_name="User",
372-
)
343+
self.user = UserFactory()
373344

374345
def test_invalid_chore_type_raises_exception(self):
375346
"""Test that invalid chore type raises exception"""
@@ -390,12 +361,7 @@ def test_invalid_chore_type_raises_exception(self):
390361

391362
class InvalidReminderTypeTest(TestCase):
392363
def setUp(self):
393-
self.user = User.objects.create_user(
394-
395-
password="testpass123",
396-
first_name="Test",
397-
last_name="User",
398-
)
364+
self.user = UserFactory()
399365

400366
def test_invalid_reminder_type_raises_exception(self):
401367
"""Test that invalid reminder type raises exception"""
@@ -430,12 +396,7 @@ def test_invalid_reminder_type_raises_exception(self):
430396

431397
class MultipleVolunteersTest(TestCase):
432398
def setUp(self):
433-
self.user = User.objects.create_user(
434-
435-
password="testpass123",
436-
first_name="Test",
437-
last_name="User",
438-
)
399+
self.user = UserFactory()
439400

440401
@time_machine.travel("2025-07-13 21:56")
441402
def test_multiple_volunteers_reminder(self):
@@ -463,17 +424,11 @@ def test_multiple_volunteers_reminder(self):
463424
)
464425

465426
# Create multiple volunteers
466-
volunteer1 = User.objects.create_user(
427+
volunteer1 = UserFactory(
467428
468-
password="testpass123",
469-
first_name="Volunteer1",
470-
last_name="User",
471429
)
472-
volunteer2 = User.objects.create_user(
430+
volunteer2 = UserFactory(
473431
474-
password="testpass123",
475-
first_name="Volunteer2",
476-
last_name="User",
477432
)
478433

479434
ChoreVolunteer.objects.create(
@@ -496,18 +451,13 @@ def test_multiple_volunteers_reminder(self):
496451

497452
# Check that both volunteers received notifications
498453
notification_emails = [email.to[0] for email in mail.outbox]
499-
self.assertIn("volunteer1@example.com", notification_emails)
500-
self.assertIn("volunteer2@example.com", notification_emails)
454+
self.assertIn(volunteer1.email, notification_emails)
455+
self.assertIn(volunteer2.email, notification_emails)
501456

502457

503458
class MultipleChoresTest(TestCase):
504459
def setUp(self):
505-
self.user = User.objects.create_user(
506-
507-
password="testpass123",
508-
first_name="Test",
509-
last_name="User",
510-
)
460+
self.user = UserFactory()
511461

512462
@time_machine.travel("2025-07-10 19:56")
513463
def test_multiple_chores_processed(self):
@@ -592,12 +542,7 @@ def test_multiple_chores_processed(self):
592542

593543
class NoChoresTest(TestCase):
594544
def setUp(self):
595-
self.user = User.objects.create_user(
596-
597-
password="testpass123",
598-
first_name="Test",
599-
last_name="User",
600-
)
545+
self.user = UserFactory()
601546

602547
@time_machine.travel("2025-07-10 19:56")
603548
def test_no_chores_no_emails(self):
@@ -612,12 +557,7 @@ def test_no_chores_no_emails(self):
612557

613558
class FutureEventTest(TestCase):
614559
def setUp(self):
615-
self.user = User.objects.create_user(
616-
617-
password="testpass123",
618-
first_name="Test",
619-
last_name="User",
620-
)
560+
self.user = UserFactory()
621561

622562
@time_machine.travel("2025-07-10 19:56")
623563
def test_future_event_no_reminder(self):
@@ -665,12 +605,7 @@ class VolunteerCrossContaminationTest(TestCase):
665605
"""Test the defect where volunteers from one chore incorrectly affect another chore's reminder logic"""
666606

667607
def setUp(self):
668-
self.user = User.objects.create_user(
669-
670-
password="testpass123",
671-
first_name="Test",
672-
last_name="User",
673-
)
608+
self.user = UserFactory()
674609

675610
@time_machine.travel("2025-07-10 19:56")
676611
def test_volunteer_cross_contamination_defect(self):
@@ -740,12 +675,7 @@ def test_volunteer_cross_contamination_defect(self):
740675
)
741676

742677
# Create a volunteer for chore1 only
743-
volunteer = User.objects.create_user(
744-
745-
password="testpass123",
746-
first_name="Volunteer",
747-
last_name="User",
748-
)
678+
volunteer = UserFactory()
749679
ChoreVolunteer.objects.create(
750680
user=volunteer,
751681
chore=chore1, # Only volunteer for chore1

chores/tests/test_models.py

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@
22
from django.core.exceptions import ValidationError
33
from django.test import TestCase
44

5-
from members.models import User
6-
75
from ..models import Chore, ChoreNotification, ChoreVolunteer
6+
from .factories import UserFactory
87

98

109
class ChoreModelTest(TestCase):
1110
def setUp(self):
12-
self.user = User.objects.create_user(
13-
14-
password="testpass123",
15-
first_name="Test",
16-
last_name="User",
17-
)
11+
self.user = UserFactory()
1812

1913
def test_chore_creation(self):
2014
"""Test basic chore creation"""
@@ -63,12 +57,7 @@ def test_chore_unique_name_constraint(self):
6357

6458
class ChoreVolunteerModelTest(TestCase):
6559
def setUp(self):
66-
self.user = User.objects.create_user(
67-
68-
password="testpass123",
69-
first_name="Test",
70-
last_name="User",
71-
)
60+
self.user = UserFactory()
7261
self.chore = Chore.objects.create(
7362
name="Test Chore",
7463
description="A test chore",
@@ -95,18 +84,13 @@ def test_chore_volunteer_properties(self):
9584
chore=self.chore,
9685
timestamp=1753041600,
9786
)
98-
self.assertEqual(volunteer.first_name, "Test")
99-
self.assertEqual(volunteer.full_name, "Test User")
87+
self.assertEqual(volunteer.first_name, self.user.first_name)
88+
self.assertEqual(volunteer.full_name, self.user.full_name)
10089

10190

10291
class ChoreNotificationModelTest(TestCase):
10392
def setUp(self):
104-
self.user = User.objects.create_user(
105-
106-
password="testpass123",
107-
first_name="Test",
108-
last_name="User",
109-
)
93+
self.user = self.user = UserFactory()
11094
self.chore = Chore.objects.create(
11195
name="Test Chore",
11296
description="A test chore",
@@ -167,5 +151,5 @@ def test_notification_str_representation(self):
167151
recipient_user=self.user,
168152
)
169153
self.assertIn("Notification to", str(notification))
170-
self.assertIn("Test User", str(notification))
154+
self.assertIn(self.user.full_name, str(notification))
171155
self.assertIn("Test Chore", str(notification))

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ dependencies = [
4545
"croniter>=6.0.0",
4646
"humanize>=4.12.3",
4747
"time-machine>=2.16.0",
48+
"factory-boy>=3.3.3",
4849
]
4950

5051
[dependency-groups]

uv.lock

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)