agentleFS
kjnezkjnez/claude-code-django/.claude/skills/pytest-django-patterns/SKILL.md

pytest-django-patterns

Skill177 starsChanged 10 months agoMITView on GitHub

pytest-django testing patterns, Factory Boy, fixtures, and TDD workflow. Use when writing tests, creating test factories, or following TDD red-green-refactor cycle.

We split this skill into the rules it gives an agent

30 rules. About 0 are common, 15 are distinctive, and 15 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈15

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 15

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    RED: Write a failing test first that describes desired behavior

    line 12
  2. Distinctive:

    GREEN: Write minimal code to make the test pass

    line 13
  3. Distinctive:

    REPEAT: Never write production code without a failing test

    line 15
  4. Distinctive:

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

    line 17
  5. Very specific:

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

    line 23
  6. Very specific:

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

    line 31
  7. Very specific:

    Use factory.Sequence() for unique fields

    line 32
  8. Very specific:

    Use factory.Faker() for realistic fake data

    line 33
  9. Very specific:

    Use factory.SubFactory() for foreign keys

    line 34
  10. Very specific:

    Use @factory.post_generation for M2M relationships

    line 35
  11. Very specific:

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

    line 39
  12. Very specific:

    Use @pytest.mark.parametrize for testing multiple scenarios

    line 59
  13. Very specific:

    HTMX: Check HTTP_HX_REQUEST header returns partial template

    line 69
  14. Distinctive:

    Test logic only: Don't test actual async execution

    line 85
  15. Very specific:

    Check partial template rendered when HX-Request header present:

    line 92
  16. Distinctive:

    Create authenticated vs anonymous client fixtures:

    line 98
  17. Distinctive:

    Test redirect/403 for unauthorized access

    line 99
  18. Distinctive:

    Test success for authorized access

    line 100
  19. Distinctive:

    Create test data with factories

    line 105
  20. Very specific:

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

    line 108
  21. Very specific:

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

    line 114
  22. Very specific:

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

    line 119
  23. Very specific:

    Use mocker.patch() to avoid actual HTTP calls, emails, file operations

    line 122
  24. Very specific:

    Use refresh_from_db() to verify updates

    line 127
  25. Distinctive:

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

    line 150
  26. Distinctive:

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

    line 153
  27. Distinctive:

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

    line 170
  28. Distinctive:

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

    line 171
  29. Distinctive:

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

    line 172
  30. Distinctive:

    celery-patterns: Test task logic with mocked external dependencies

    line 173

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.