Skip to content

Commit 107736b

Browse files
committed
add small unit testing
1 parent 78b271c commit 107736b

1 file changed

Lines changed: 251 additions & 0 deletions

File tree

todo/tests.py

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
from rest_framework.test import APITestCase
2+
from rest_framework import status
3+
from django.contrib.auth.models import User
4+
from .models import Todo
5+
from django.urls import reverse # Used to get URLs by name
6+
7+
8+
# Test cases inherit from APITestCase
9+
class TodoAPITests(APITestCase):
10+
def setUp(self):
11+
"""
12+
This method runs *before* every single test.
13+
It's used to set up a clean environment.
14+
"""
15+
16+
# Create User 1
17+
self.user1 = User.objects.create_user(
18+
username="user1@test.com",
19+
email="user1@test.com",
20+
password="password123",
21+
first_name="User1",
22+
)
23+
24+
# Create User 2
25+
self.user2 = User.objects.create_user(
26+
username="user2@test.com",
27+
email="user2@test.com",
28+
password="password123",
29+
first_name="User2",
30+
)
31+
32+
# Create a task for User 1
33+
self.task1 = Todo.objects.create(owner=self.user1, title="User 1 Task")
34+
35+
# Create a task for User 2
36+
self.task2 = Todo.objects.create(owner=self.user2, title="User 2 Task")
37+
38+
# --- Authentication Tests ---
39+
40+
def test_user_can_register(self):
41+
"""
42+
Test that a new user can register.
43+
"""
44+
url = "/register/" # Or reverse('user-register')
45+
data = {
46+
"name": "NewUser",
47+
"email": "newuser@test.com",
48+
"password": "password123",
49+
}
50+
response = self.client.post(url, data)
51+
52+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
53+
self.assertEqual(User.objects.count(), 3)
54+
self.assertEqual(response.data["name"], "NewUser")
55+
56+
def test_user_cannot_register_with_existing_email(self):
57+
"""
58+
Test that a user cannot register with an email (username) that already exists.
59+
"""
60+
url = "/register/"
61+
data = {
62+
"name": "AnotherUser",
63+
"email": "user1@test.com", # This email is already taken
64+
"password": "password123",
65+
}
66+
response = self.client.post(url, data)
67+
68+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
69+
self.assertEqual(User.objects.count(), 2) # No new user was created
70+
71+
def test_user_can_login(self):
72+
"""
73+
Test that a user can log in with correct email and password.
74+
"""
75+
url = "/login/" # Or reverse('token_obtain_pair')
76+
data = {"email": "user1@test.com", "password": "password123"}
77+
response = self.client.post(url, data)
78+
79+
self.assertEqual(response.status_code, status.HTTP_200_OK)
80+
self.assertIn("access", response.data)
81+
self.assertIn("refresh", response.data)
82+
83+
def test_user_cannot_login_with_wrong_password(self):
84+
"""
85+
Test that login fails with an incorrect password.
86+
"""
87+
url = "/login/"
88+
data = {"email": "user1@test.com", "password": "wrongpassword"}
89+
response = self.client.post(url, data)
90+
91+
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
92+
93+
# --- Todo List/Create Tests (Security) ---
94+
95+
def test_unauthenticated_user_cannot_list_todos(self):
96+
"""
97+
Test that a user who is not logged in gets a 401 error.
98+
"""
99+
# We do NOT call self.client.force_authenticate()
100+
url = "/todos/"
101+
response = self.client.get(url)
102+
103+
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
104+
105+
def test_authenticated_user_can_create_todo(self):
106+
"""
107+
Test that a logged-in user can create a new todo.
108+
"""
109+
self.client.force_authenticate(user=self.user1)
110+
url = "/todos/"
111+
data = {"title": "New Task", "description": "Test description"}
112+
113+
response = self.client.post(url, data)
114+
115+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
116+
self.assertEqual(Todo.objects.count(), 3)
117+
new_task = Todo.objects.get(title="New Task")
118+
self.assertEqual(new_task.owner, self.user1)
119+
120+
def test_user_can_only_see_own_todos(self):
121+
"""
122+
Test that a user cannot see tasks owned by other users.
123+
"""
124+
self.client.force_authenticate(user=self.user1)
125+
url = "/todos/"
126+
127+
response = self.client.get(url)
128+
129+
self.assertEqual(response.status_code, status.HTTP_200_OK)
130+
# Check paginated response
131+
self.assertEqual(len(response.data["results"]), 1)
132+
self.assertEqual(response.data["results"][0]["title"], "User 1 Task")
133+
134+
# --- Todo Detail (Retrieve, Update, Delete) Tests ---
135+
136+
def test_user_can_retrieve_own_todo(self):
137+
"""
138+
Test that a user can get the details of their own task.
139+
"""
140+
self.client.force_authenticate(user=self.user1)
141+
url = f"/todos/{self.task1.id}/" # e.g., /todos/1/
142+
143+
response = self.client.get(url)
144+
145+
self.assertEqual(response.status_code, status.HTTP_200_OK)
146+
self.assertEqual(response.data["title"], self.task1.title)
147+
148+
def test_user_cannot_retrieve_other_users_todo(self):
149+
"""
150+
Test security: A user cannot get the details of another user's task.
151+
"""
152+
self.client.force_authenticate(user=self.user1)
153+
url = f"/todos/{self.task2.id}/" # Task 2 belongs to User 2
154+
155+
response = self.client.get(url)
156+
157+
# Should return 404 Not Found, as if the task doesn't exist
158+
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
159+
160+
def test_user_can_update_own_todo(self):
161+
"""
162+
Test that a user can update their own task.
163+
"""
164+
self.client.force_authenticate(user=self.user1)
165+
url = f"/todos/{self.task1.id}/"
166+
data = {"title": "UPDATED Task Title", "description": "Updated desc."}
167+
168+
response = self.client.put(url, data)
169+
170+
self.assertEqual(response.status_code, status.HTTP_200_OK)
171+
self.assertEqual(response.data["title"], "UPDATED Task Title")
172+
173+
# Verify the change in the database
174+
self.task1.refresh_from_db()
175+
self.assertEqual(self.task1.title, "UPDATED Task Title")
176+
177+
def test_user_cannot_update_other_users_todo(self):
178+
"""
179+
Test security: A user cannot update another user's task.
180+
"""
181+
self.client.force_authenticate(user=self.user1)
182+
url = f"/todos/{self.task2.id}/" # Task 2 belongs to User 2
183+
data = {"title": "I am hacking you"}
184+
185+
response = self.client.put(url, data)
186+
187+
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
188+
189+
def test_user_can_delete_own_todo(self):
190+
"""
191+
Test that a user can delete their own task.
192+
"""
193+
self.client.force_authenticate(user=self.user1)
194+
url = f"/todos/{self.task1.id}/"
195+
196+
response = self.client.delete(url)
197+
198+
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
199+
self.assertFalse(Todo.objects.filter(id=self.task1.id).exists())
200+
201+
def test_user_cannot_delete_other_users_todo(self):
202+
"""
203+
Test security: A user cannot delete another user's task.
204+
"""
205+
self.client.force_authenticate(user=self.user1)
206+
url = f"/todos/{self.task2.id}/" # Task 2 belongs to User 2
207+
208+
response = self.client.delete(url)
209+
210+
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
211+
self.assertTrue(Todo.objects.filter(id=self.task2.id).exists())
212+
213+
# --- Toggle Complete Test ---
214+
215+
def test_user_can_toggle_complete_own_todo(self):
216+
"""
217+
Test that a user can toggle their task's 'completed' status.
218+
"""
219+
self.client.force_authenticate(user=self.user1)
220+
url = f"/todos/{self.task1.id}/complete/"
221+
222+
# Check it's False to begin with
223+
self.assertFalse(self.task1.completed)
224+
225+
# First toggle: should become True
226+
response = self.client.put(url)
227+
self.assertEqual(response.status_code, status.HTTP_200_OK)
228+
self.assertEqual(response.data["completed"], True)
229+
230+
# Check in the database
231+
self.task1.refresh_from_db()
232+
self.assertTrue(self.task1.completed)
233+
234+
# Second toggle: should become False
235+
response = self.client.put(url)
236+
self.assertEqual(response.status_code, status.HTTP_200_OK)
237+
self.assertEqual(response.data["completed"], False)
238+
239+
self.task1.refresh_from_db()
240+
self.assertFalse(self.task1.completed)
241+
242+
def test_user_cannot_toggle_other_users_todo(self):
243+
"""
244+
Test security: A user cannot toggle another user's task.
245+
"""
246+
self.client.force_authenticate(user=self.user1)
247+
url = f"/todos/{self.task2.id}/complete/" # Task 2 belongs to User 2
248+
249+
response = self.client.put(url)
250+
251+
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

0 commit comments

Comments
 (0)