pytest-django-patterns

pytest-django Testing Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "pytest-django-patterns" with this command: npx skills add kjnez/claude-code-django/kjnez-claude-code-django-pytest-django-patterns

pytest-django Testing Patterns

TDD Workflow (RED-GREEN-REFACTOR)

Always follow this cycle:

  • RED: Write a failing test first that describes desired behavior

  • GREEN: Write minimal code to make the test pass

  • REFACTOR: Clean up code while keeping tests green

  • REPEAT: Never write production code without a failing test

Critical rule: If implementing a feature or fixing a bug, write the test BEFORE touching production code.

Essential pytest-django Patterns

Database Access

  • Use @pytest.mark.django_db on any test touching the database

  • Apply to entire module: pytestmark = pytest.mark.django_db

  • Transactions roll back automatically after each test

Fixtures for Test Data

Use Factory Boy for models, pytest fixtures for setup:

Factories: Create model instances with realistic data (UserFactory() )

  • Use factory.Sequence() for unique fields

  • Use factory.Faker() for realistic fake data

  • Use factory.SubFactory() for foreign keys

  • Use @factory.post_generation for M2M relationships

Fixtures: Setup clients, auth state, or shared resources

  • client fixture: Django test client

  • Create auth_client fixture: client.force_login(user) for authenticated requests

  • Define in conftest.py for reuse across test files

Test Organization

Structure tests to mirror app structure:

tests/ ├── apps/ │ └── posts/ │ ├── test_models.py │ ├── test_views.py │ └── test_forms.py ├── factories.py └── conftest.py

Group related tests in classes:

  • Name classes TestComponentName (e.g., TestPostListView )

  • Name test methods descriptively: test_<action>_<expected_outcome>

  • Use @pytest.mark.parametrize for testing multiple scenarios

What to Test

Views

  • Status codes: Correct HTTP responses (200, 404, 302)

  • Authentication: Authenticated vs anonymous behavior

  • Authorization: User can only access their own data

  • Context data: Correct objects passed to template

  • Side effects: Database changes, emails sent, tasks queued

  • HTMX: Check HTTP_HX_REQUEST header returns partial template

Forms

  • Validation: Valid data passes, invalid data fails with correct errors

  • Edge cases: Empty fields, max lengths, unique constraints

  • Clean methods: Custom validation logic works

  • Save behavior: Objects created/updated correctly

Models

  • Methods: str , custom methods return expected values

  • Managers/QuerySets: Custom filtering works correctly

  • Constraints: Database-level validation enforced

  • Signals: Pre/post save hooks execute correctly

Celery Tasks

  • Mock external calls: Patch HTTP requests, email sending, etc.

  • Test logic only: Don't test actual async execution

  • Idempotency: Running task multiple times is safe

Django-Specific Testing Patterns

Testing HTMX Responses

Check partial template rendered when HX-Request header present:

  • Pass HTTP_HX_REQUEST="true" to client request

  • Assert response.templates contains partial template name

Testing Permissions

Create authenticated vs anonymous client fixtures:

  • Test redirect/403 for unauthorized access

  • Test success for authorized access

Testing QuerySets

Verify efficient queries:

  • Create test data with factories

  • Execute query

  • Assert correct objects returned/excluded

  • Verify related objects loaded with select_related() /prefetch_related()

Testing Forms with Model Instances

Pass instance to form for updates:

  • form = MyForm(data=new_data, instance=existing_obj)

  • Verify form.save() updates, doesn't create

Common Patterns

Parametrize multiple scenarios: Use @pytest.mark.parametrize("input,expected", [...]) for testing various inputs

Mock external services: Use mocker.patch() to avoid actual HTTP calls, emails, file operations

Check database changes:

  • Assert Model.objects.filter(...).exists() after creation

  • Assert Model.objects.count() == expected for deletions

  • Use refresh_from_db() to verify updates

Test error handling:

  • Invalid form data produces correct errors

  • Failed operations return error responses

  • User sees appropriate error messages

Running Tests

uv run pytest # All tests uv run pytest -x # Stop on first failure uv run pytest --lf # Run last failed uv run pytest -x --lf # Stop first, last failed only uv run pytest -k "test_name" # Run tests matching pattern uv run pytest tests/apps/posts/ # Specific directory uv run pytest --cov=apps # With coverage report

Common Pitfalls

  • Forgetting @pytest.mark.django_db : Results in "Database access not allowed" errors

  • Not using factories: Creating instances manually is verbose and brittle

  • Testing implementation: Test behavior and outcomes, not internal implementation details

  • Skipping TDD: Writing tests after code means tests follow implementation, missing edge cases

  • Over-mocking: Mock external dependencies, not your own code

  • Testing framework code: Don't test Django's ORM, form validation, etc. Test YOUR logic

Setup Requirements

In pyproject.toml :

[tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "config.settings.test" python_files = ["test_*.py"] addopts = ["--reuse-db", "-ra"]

In conftest.py : Define shared fixtures (auth_client, common factories, etc.)

Integration with Other Skills

  • systematic-debugging: When fixing bugs, write failing test first to reproduce

  • django-models: Test custom managers, QuerySets, and model methods

  • django-forms: Test form validation, clean methods, and save behavior

  • celery-patterns: Test task logic with mocked external dependencies

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

htmx-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

django-templates

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

django-forms

No summary provided by upstream source.

Repository SourceNeeds Review