Integration Testing
This guide explains how to write integration tests for the Gyrinx application using Django's test client and pytest.
Overview
Integration tests verify complete user workflows through the UI, ensuring all components work together correctly. They use Django's test client to simulate HTTP requests and responses, testing the full stack from URLs to views to models.
Test Structure
Integration tests follow these conventions:
File naming: Use
test_integration_*.pyfor integration test filesFunction naming: Use descriptive names that explain the workflow being tested
Decorators: Always use
@pytest.mark.django_dbfor tests that access the database
Basic Pattern
@pytest.mark.django_db
def test_user_workflow(client, user, other_fixtures):
"""Test description of what workflow is being tested."""
# 1. Login user if authentication is required
client.force_login(user)
# 2. Make GET request to view page
response = client.get(reverse("app:view-name", args=[obj.id]))
assert response.status_code == 200
assert "Expected content" in response.content.decode()
# 3. Make POST request to submit form
response = client.post(
reverse("app:action-name", args=[obj.id]),
{
"field1": "value1",
"field2": "value2",
}
)
assert response.status_code == 302 # Redirect after success
# 4. Verify database changes
obj.refresh_from_db()
assert obj.field1 == "value1"
# 5. Verify UI reflects changes
response = client.get(reverse("app:view-name", args=[obj.id]))
assert "value1" in response.content.decode()Available Fixtures
The project provides several fixtures in conftest.py:
client: Django test client for making HTTP requestsuser: A test user instancemake_user: Factory for creating userscontent_house: A ContentHouse instancemake_content_house: Factory for creating housescontent_fighter: A ContentFighter instancemake_content_fighter: Factory for creating fightersmake_list: Factory for creating listsmake_list_fighter: Factory for creating list fightersmake_equipment: Factory for creating equipmentmake_weapon_profile: Factory for creating weapon profilesmake_weapon_accessory: Factory for creating weapon accessories
Common Test Scenarios
Testing Authentication
Testing Form Submissions
Testing Permissions
Testing Search and Filtering
Best Practices
Test complete workflows: Integration tests should cover entire user journeys, not just individual views
Use descriptive assertions: Check for specific content in responses to ensure the right template and data are rendered
Test error cases: Verify that invalid inputs are handled gracefully
Clean test data: Tests should create their own data and not depend on existing database state
Test permissions: Always verify that unauthorized users cannot access protected resources
Use factories: Leverage the provided fixture factories to create test data consistently
Running Integration Tests
Run all integration tests:
Run a specific test:
Run with verbose output:
Debugging Tips
Print response content: When a test fails, print
response.content.decode()to see the actual HTMLCheck redirects: Use
response.urlto see where a redirect is goingExamine form errors: Access
response.context['form'].errorsto see validation errorsDatabase state: Use
Model.objects.all()to verify database changesUse pdb: Add
import pdb; pdb.set_trace()to debug interactively
Example: Complete Integration Test
Here's a complete example testing the fighter equipment workflow:
This example demonstrates:
Setting up test data with fixtures
Making authenticated requests
Testing multiple related views
Verifying database changes
Checking UI updates reflect data changes
Last updated