Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Models, Views, Admin and Tests  ›  Capstone Project

tests.py — Proving It Works

tests.py 16 minDjango tests in tests.py subclass TestCase, run against a temporary test database, and use the test client to send fake requests and check the responses.

tests.py — Proving It Works

You changed the recipe URLs last week. Did the search page break? The detail page? The only honest way to know, every time, is to have the computer check. Django's test tools can pretend to be a browser, visit your pages and verify the answers in seconds.

The rule

Arrange data, send a fake request, assert on the response.

# recipes/tests.py
from django.test import TestCase
from django.urls import reverse
from .models import Recipe

class RecipeDetailTests(TestCase):
    def setUp(self):
        Recipe.objects.create(title="Tomato soup", slug="tomato-soup", minutes=25)

    def test_shows_recipe(self):
        url = reverse("recipes:detail", args=["tomato-soup"])
        response = self.client.get(url)
        self.assertContains(response, "Tomato soup")

    def test_missing_recipe_is_404(self):
        url = reverse("recipes:detail", args=["no-such-dish"])
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

The parts:

  • TestCase from django.test, not plain unittest. It adds the test client and database handling.
  • Methods whose names start with test are tests; others, like setUp, are helpers. setUp runs before each test.
  • self.client sends requests through the whole stack, middleware, URLs, view and template, without a real server.
  • assertContains checks the status is 200 and the text appears in the page.
  • reverse() again: tests use names, so they survive URL changes too.

Run them:

python manage.py test recipes

Your real data is safe. Django creates a separate test database for the run and destroys it afterwards, and TestCase rolls back every test's changes, so tests never see each other's rows.

What to test first: each page loads, missing objects give 404, and any rule you care about, such as "quick recipes excludes a 45-minute stew".

The shortcut

Every test is three beats: arrange, act, assert. Create just enough data, make one request or call, check one behaviour. If a test needs a paragraph to explain, split it.

Testing "quick recipes excludes the stew"Step 1 of 4
  1. Arrange

    Create a 25-minute soup and a 45-minute stew.

The trap is a test that never fails. Break the view on purpose once and watch the test go red; then you know it guards something.

Drills

Answer fast — trust the rule.

quick drill

Which method name will Django run as a test?

quick drill

Does python manage.py test read and change your real db.sqlite3 recipes?

quick drill

self.assertContains(response, "Tomato soup") checks which two things?

quick drill

What does self.client.get(url) do in a test?

quick drill

In the arrange-act-assert rhythm, which line is "act"?

Remember

  • Arrange data, send a fake request, assert on the response.
  • TestCase, test_ names, self.client, and reverse() for URLs.
  • Trap: a test you have never seen fail may not be testing anything.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainTest the detail page

Write two tests for the cookbook's recipe detail page: one showing an existing recipe and one for a slug that does not exist. Explain what each line does and why the tests cannot damage your real recipes.