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
- Distinctive: line 12
RED: Write a failing test first that describes desired behavior
- Distinctive: line 13
GREEN: Write minimal code to make the test pass
- Distinctive: line 15
REPEAT: Never write production code without a failing test
- Distinctive: line 17
Critical rule: If implementing a feature or fixing a bug, write the test BEFORE touching production code.
- Very specific: line 23
Use @pytest.mark.django_db on any test touching the database
- Very specific: line 31
Factories: Create model instances with realistic data (UserFactory())
- Very specific: line 32
Use factory.Sequence() for unique fields
- Very specific: line 33
Use factory.Faker() for realistic fake data
- Very specific: line 34
Use factory.SubFactory() for foreign keys
- Very specific: line 35
Use @factory.post_generation for M2M relationships
- Very specific: line 39
Create auth_client fixture: client.force_login(user) for authenticated requests
- Very specific: line 59
Use @pytest.mark.parametrize for testing multiple scenarios
- Very specific: line 69
HTMX: Check HTTP_HX_REQUEST header returns partial template
- Distinctive: line 85
Test logic only: Don't test actual async execution
- Very specific: line 92
Check partial template rendered when HX-Request header present:
- Distinctive: line 98
Create authenticated vs anonymous client fixtures:
- Distinctive: line 99
Test redirect/403 for unauthorized access
- Distinctive: line 100
Test success for authorized access
- Distinctive: line 105
Create test data with factories
- Very specific: line 108
Verify related objects loaded with select_related()/prefetch_related()
- Very specific: line 114
Verify form.save() updates, doesn't create
- Very specific: line 119
Use @pytest.mark.parametrize("input,expected", [...]) for testing various inputs
- Very specific: line 122
Use mocker.patch() to avoid actual HTTP calls, emails, file operations
- Very specific: line 127
Use refresh_from_db() to verify updates
- Distinctive: line 150
Testing implementation: Test behavior and outcomes, not internal implementation details
- Distinctive: line 153
Testing framework code: Don't test Django's ORM, form validation, etc.
- Distinctive: line 170
systematic-debugging: When fixing bugs, write failing test first to reproduce
- Distinctive: line 171
django-models: Test custom managers, QuerySets, and model methods
- Distinctive: line 172
django-forms: Test form validation, clean methods, and save behavior
- Distinctive: line 173
celery-patterns: Test task logic with mocked external dependencies
≈ “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.
Files
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_dbon 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_generationfor M2M relationships
- Use
- Fixtures: Setup clients, auth state, or shared resources
clientfixture: Django test client- Create
auth_clientfixture:client.force_login(user)for authenticated requests - Define in
conftest.pyfor 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.pyGroup related tests in classes:
- Name classes
TestComponentName(e.g.,TestPostListView) - Name test methods descriptively:
test_<action>_<expected_outcome> - Use
@pytest.mark.parametrizefor 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_REQUESTheader 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.templatescontains 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() == expectedfor 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 reportCommon 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
In this repository16 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- celery-patternsSkill
- code-qualitySkill
- django-extensionsSkill
- django-formsSkill
- django-modelsSkill
- django-templatesSkill
- docs-syncSkill
- htmx-patternsSkill
- onboardSkill
- pr-reviewSkill
- pr-summarySkill
- skill-creatorSkill
- systematic-debuggingSkill
- ticketSkill
- worktree-commit-mergeSkill
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.

