Unit Testing0%

Unit Testing

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Unit Testing

Enterprise software requires continuous confidence that code modifications do not introduce regressions into models, business logic, authorization rules, or view routing. Django provides an automated testing framework built atop Python's standard unittest library, featuring an isolated test database runner, mock HTTP request clients, and specialized assertions.


1. The Django Test Runner Lifecycle

When you execute python manage.py test:

  1. 1
    Django constructs a temporary, isolated test database in memory or on disk.
  2. 2
    It executes all pending migrations to build the schema from scratch.
  3. 3
    Tests run in clean, transaction-isolated sandboxes (each test method rolls back database mutations upon completion).
  4. 4
    The temporary test database is destroyed upon completion.
  5. 5
    Your development and production databases remain 100% untouched!

2. Unit Testing Models

Test model validations, default values, custom methods, and __str__ representations:

Python
# articles/tests/test_models.py
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from articles.models import Article
 
User = get_user_model()
 
class ArticleModelTest(TestCase):
def setUp(self):
# Runs BEFORE every test method
self.user = User.objects.create_user(
email="author@enterprise.com",
username="author",
password="SecurePassword123!"
)
 
def test_article_creation_and_slug_generation(self):
article = Article.objects.create(
title="Advanced Django ORM Patterns",
content="Comprehensive guide to QuerySets...",
author=self.user,
status="published"
)
 
# Assertions
self.assertEqual(str(article), "Advanced Django ORM Patterns (published)")
self.assertEqual(article.slug, "advanced-django-orm-patterns")
self.assertEqual(article.view_count, 0)
self.assertTrue(article.created_at is not None)
 
def test_draft_articles_cannot_be_featured(self):
article = Article(
title="Draft Title",
content="Content...",
author=self.user,
status="draft",
is_featured=True
)
# Verify clean() method raises ValidationError
with self.assertRaises(ValidationError):
article.clean()

3. Testing Views with Client

Django's Client acts as a dummy web browser, simulating GET and POST requests without running a live HTTP network server:

Python
# articles/tests/test_views.py
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth import get_user_model
from articles.models import Article
 
User = get_user_model()
 
class ArticleViewTest(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user(
email="editor@enterprise.com",
username="editor",
password="Password123"
)
self.article = Article.objects.create(
title="Test Story",
slug="test-story",
content="Sample text",
author=self.user,
status="published"
)
 
def test_article_list_view_status_code_and_template(self):
url = reverse("articles:home")
response = self.client.get(url)
 
# Assert HTTP 200 OK
self.assertEqual(response.status_code, 200)
# Assert template used
self.assertTemplateUsed(response, "articles/home.html")
# Assert context contains articles
self.assertIn(self.article, response.context["articles"])
 
def test_create_article_requires_authentication(self):
url = reverse("articles:create")
# Attempt access as anonymous guest
response = self.client.get(url)
# Should redirect to login page (HTTP 302)
self.assertEqual(response.status_code, 302)
self.assertIn("/accounts/login/", response.url)
 
def test_authenticated_user_can_create_article(self):
# Authenticate simulated client
self.client.force_login(self.user)
url = reverse("articles:create")
 
payload = {
"title": "New Testing Article",
"content": "Body text for test.",
"status": "published",
}
response = self.client.post(url, data=payload)
 
# Assert successful creation redirects to detail view
self.assertEqual(response.status_code, 302)
self.assertTrue(Article.objects.filter(title="New Testing Article").exists())

4. Running Tests with Code Coverage

Measure test completeness using coverage.py:

Bash / Terminal
# Run tests under coverage measurement
coverage run --source='.' manage.py test
 
# Display terminal coverage report
coverage report
 
# Generate interactive HTML coverage dashboard
coverage html

Aim for >85% coverage across enterprise business logic.


Interactive Quiz

Practice Quiz

Question 1
What happens to the database when you run python manage.py test?
Question 2
Why does TestCase wrap each individual test method inside a database transaction?
Question 3
What does self.client.force_login(user) accomplish in a Django test?
Question 4
Which assertion verifies that an unauthenticated user is redirected to the login page?
Question 5
What tool is standard in Python for measuring the percentage of codebase lines executed during tests?
Next Lesson

Debugging Tips

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext