Labs ICT
โญ Pro Login

Testing

Writing tests for your Django app.

Why Test Your Django Apps?

Testing isn't optional โ€” it's what separates a fragile project from a reliable one. Django makes testing surprisingly easy with a built-in test framework based on Python's unittest. You can test models, views, forms, templates, and anything else in your project.

The best part? Django's test runner creates a fresh database for each test run, so your tests never pollute your real data. Run python manage.py test and you're good to go.

Testing Models

Model tests verify your business logic works correctly. Use Django's TestCase which wraps each test in a database transaction for speed.

from django.test import TestCase
from .models import Post

class PostModelTest(TestCase):
    def setUp(self):
        self.post = Post.objects.create(
            title='Test Post',
            content='Hello World',
            author='admin'
        )

    def test_post_creation(self):
        self.assertEqual(self.post.title, 'Test Post')
        self.assertFalse(self.post.published)

    def test_post_str(self):
        self.assertEqual(str(self.post), 'Test Post')

The setUp method runs before each test, giving you a clean starting point. Create the objects you need once and test different aspects of them.

Testing Views

Django's test Client simulates HTTP requests so you can test views without starting a server. Check responses, status codes, and even what got rendered.

from django.test import TestCase, Client
from django.urls import reverse

class PostViewTest(TestCase):
    def setUp(self):
        self.client = Client()
        self.url = reverse('post_list')

    def test_post_list_view(self):
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Posts')

    def test_redirect_on_post(self):
        response = self.client.post(self.url, {'title': 'New'})
        self.assertEqual(response.status_code, 302)

The reverse() function generates URLs from their names, so you don't hardcode paths in your tests. If you rename a URL, your tests still work.

Try it Yourself โ†’

Fixtures and Factories

Fixtures let you load test data from JSON or YAML files. They're great for complex datasets, but can become hard to maintain as your project grows.

class CommentTest(TestCase):
    fixtures = ['test_data.json']

    def test_comments_loaded(self):
        self.assertEqual(Comment.objects.count(), 10)

For more flexibility, consider factory_boy. It generates test data programmatically and plays nicely with Django's ORM, making it easy to create related objects on the fly.

Test Coverage

How do you know which parts of your code aren't tested? Use coverage.py to measure which lines of code your tests actually execute. Install it with pip install coverage and run coverage run manage.py test followed by coverage report.

Aim for meaningful coverage, not just high numbers. Test the edge cases, the error paths, and the business logic that matters. A 90% coverage with smart tests beats 100% coverage with trivial ones.

๐Ÿงช Quick Quiz

Which class do you use to write tests in Django?