pytest-django-patterns

📁 kjnez/claude-code-django 📅 Jan 23, 2026
4
总安装量
2
周安装量
#53865
全站排名
安装命令
npx skills add https://github.com/kjnez/claude-code-django --skill pytest-django-patterns

Agent 安装分布

claude-code 2
opencode 1
cursor 1
codex 1
antigravity 1
gemini-cli 1

Skill 文档

pytest-django Testing Patterns

TDD Workflow (RED-GREEN-REFACTOR)

Always follow this cycle:

  1. RED: Write a failing test first that describes desired behavior
  2. GREEN: Write minimal code to make the test pass
  3. REFACTOR: Clean up code while keeping tests green
  4. 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