Good Code
The good version creates the data it needs, logs in the user, sends the intended method, and checks the database state after the request.
Lesson 10
Use Django's test client with realistic data setup and assertions that cover status, template, and database changes.
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from reviews.models import Review
class PublishReviewTests(TestCase):
def test_author_can_publish_own_review(self):
user = get_user_model().objects.create_user(
username="mira",
password="secret",
)
review = Review.objects.create(title="Draft", author=user)
self.client.force_login(user)
response = self.client.post(
reverse("reviews:publish", args=[review.pk]),
follow=True,
)
review.refresh_from_db()
self.assertEqual(response.status_code, 200)
self.assertTrue(review.is_published)
self.assertTemplateUsed(response, "reviews/detail.html")from django.test import TestCase
class PublishReviewTests(TestCase):
def test_publish_review(self):
response = self.client.get("/reviews/1/publish/")
self.assertContains(response, "Review published")The good version creates the data it needs, logs in the user, sends the intended method, and checks the database state after the request.
The bad version depends on a magic ID, uses GET for a state change, and only checks text. It can pass while the real workflow is broken.