-
Notifications
You must be signed in to change notification settings - Fork 2
DjangoMercuryAPITestCase
The investigation test case for discovering performance issues in Django applications. This class provides automatic performance monitoring, intelligent threshold management, and educational guidance.
DjangoMercuryAPITestCase is designed for the investigation phase of performance testing. It automatically monitors all test methods, discovers performance issues, and provides educational guidance on how to fix them.
- 🔍 Automatic performance monitoring for all tests
- 🎯 Smart threshold management based on operation type
- 🚨 N+1 query detection with severity analysis
- 📊 Performance scoring with letter grades (S, A+, A, B, C, D, F)
- 📚 Educational guidance for performance issues
- 🔄 Two-phase workflow support (Investigation → Documentation)
from django_mercury import DjangoMercuryAPITestCase
class MyAPITestCase(DjangoMercuryAPITestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.configure_mercury(
enabled=True,
auto_scoring=True,
educational_guidance=True
)
def test_user_list_performance(self):
# Mercury automatically monitors this test
response = self.client.get('/api/users/')
self.assertEqual(response.status_code, 200)
# Performance is automatically analyzed and scored| Attribute | Type | Default | Description |
|---|---|---|---|
_mercury_enabled |
bool |
True |
Enable/disable Mercury monitoring |
_auto_scoring |
bool |
True |
Show performance grades |
_auto_threshold_adjustment |
bool |
True |
Smart threshold defaults |
_generate_summaries |
bool |
True |
Generate test summaries |
_verbose_reporting |
bool |
False |
Detailed output |
_educational_guidance |
bool |
True |
Show learning content |
_learning_mode |
bool |
True |
Focus on discovery |
Configure Mercury behavior for the test class.
@classmethod
def configure_mercury(
cls,
enabled: bool = True,
auto_scoring: bool = True,
auto_threshold_adjustment: bool = True,
generate_summaries: bool = True,
verbose_reporting: bool = False,
educational_guidance: bool = True
)Example:
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.configure_mercury(
enabled=True,
auto_scoring=True,
educational_guidance=True,
verbose_reporting=False # Keep output focused
)Set custom performance thresholds for all tests in the class.
@classmethod
def set_performance_thresholds(
cls,
thresholds: Dict[str, Union[int, float]]
)Parameters:
-
response_time_ms: Maximum response time in milliseconds -
query_count_max: Maximum number of database queries -
memory_overhead_mb: Maximum memory overhead in MB
Example:
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.set_performance_thresholds({
'response_time_ms': 200,
'query_count_max': 15,
'memory_overhead_mb': 30
})Set custom thresholds for the current test only.
def set_test_performance_thresholds(
self,
thresholds: Dict[str, Union[int, float]]
)Example:
def test_expensive_operation(self):
# Allow higher thresholds for this specific test
self.set_test_performance_thresholds({
'response_time_ms': 1000, # Allow 1 second
'query_count_max': 50 # Allow more queries
})
response = self.client.get('/api/expensive-operation/')
self.assertEqual(response.status_code, 200)Temporarily override thresholds within a context.
@property
def mercury_override_thresholds(self)Example:
def test_complex_operation(self):
with self.mercury_override_thresholds({'query_count_max': 100}):
# This operation is allowed to use up to 100 queries
response = self.client.get('/api/complex-endpoint/')
self.assertEqual(response.status_code, 200)Assert that performance meets excellent standards (Grade A or above).
def assert_mercury_performance_excellent(
self,
metrics: EnhancedPerformanceMetrics_Python
)Example:
def test_must_be_fast(self):
response = self.client.get('/api/critical/')
# Mercury automatically captures metrics
# You can add explicit assertions if neededAssert that performance is ready for production deployment.
def assert_mercury_performance_production_ready(
self,
metrics: EnhancedPerformanceMetrics_Python
)Mercury automatically detects operation types and applies appropriate thresholds:
| Operation | Expected Queries | Response Time | Detection Keywords |
|---|---|---|---|
list_view |
3-25 | 200ms | list, get_all, index |
detail_view |
1-10 | 150ms | detail, retrieve, get_single |
create_view |
2-15 | 250ms | create, post, add |
update_view |
2-12 | 200ms | update, put, patch, edit |
delete_view |
1-30 | 300ms | delete, destroy, remove |
search_view |
1-30 | 300ms | search, filter, query |
Mercury adjusts thresholds based on context:
# Automatically detected from test code:
- Page size (pagination)
- Relation includes (select_related/prefetch_related)
- Search complexity
- Operation typeMercury detects and explains common issues:
-
N+1 Queries
- Severity levels: LOW, MEDIUM, HIGH, SEVERE, CRITICAL
- Provides specific fix suggestions
- Shows which models are affected
-
Slow Response Times
- Identifies bottlenecks
- Suggests optimization strategies
- Recommends caching approaches
-
High Memory Usage
- Tracks memory overhead
- Identifies memory leaks
- Suggests efficient data structures
When issues are detected, Mercury provides:
📚 MERCURY EDUCATIONAL GUIDANCE
================================
🎯 Test: test_user_list
⚠️ Issue: N+1 Query Pattern Detected
🔍 Severity: HIGH
💡 SOLUTION:
Use select_related() for foreign keys:
queryset = User.objects.select_related('profile')
Use prefetch_related() for many-to-many:
queryset = User.objects.prefetch_related('groups')
📖 Learn more: https://docs.djangoproject.com/
# 1. Use DjangoMercuryAPITestCase for discovery
class InvestigationTests(DjangoMercuryAPITestCase):
def test_user_api(self):
response = self.client.get('/api/users/')
# Mercury discovers issues automaticallyOutput:
🔍 test_user_list: N+1 Query Pattern (HIGH)
→ Fix: Use select_related('profile')
After fixing issues, switch to DjangoPerformanceAPITestCase:
# 2. Document requirements with assertions
class ProductionTests(DjangoPerformanceAPITestCase):
def test_user_api(self):
with monitor_django_view("UserList") as monitor:
response = self.client.get('/api/users/')
self.assertResponseTimeLess(monitor, 100)
self.assertQueriesLess(monitor, 5)Mercury generates comprehensive summaries after all tests:
🔍 MERCURY INVESTIGATION COMPLETE
==================================
📊 Investigation Results:
Tests: 10
Avg response: 150ms
Avg queries: 12.5
📍 PRIMARY ISSUE: N+1 Query Pattern
Found in 4/10 tests
→ Next Step: Add select_related() and prefetch_related()
🔄 WORKFLOW TRANSITION:
Current: INVESTIGATION (DjangoMercuryAPITestCase) - TEMPORARY
Next: DOCUMENTATION (DjangoPerformanceAPITestCase) - PERMANENT
📋 Next Steps:
• Fix discovered performance issues
• Switch to DjangoPerformanceAPITestCase
• Add specific performance assertions
class MyTests(DjangoMercuryAPITestCase):
def test_api(self):
response = self.client.get('/api/endpoint/')
# Automatic monitoring with defaultsclass MyTests(DjangoMercuryAPITestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.set_performance_thresholds({
'response_time_ms': 100,
'query_count_max': 10
})def test_special_case(self):
self.set_test_performance_thresholds({
'response_time_ms': 500
})
# This test allows 500ms response timedef test_with_context(self):
with self.mercury_override_thresholds({'query_count_max': 50}):
# This block allows 50 queries
response = self.client.get('/api/complex/')-
Use for Investigation Only
- This class is for discovering issues
- Don't use in CI/CD pipelines
- Switch to
DjangoPerformanceAPITestCasefor production
-
Fix Issues Systematically
- Address N+1 queries first (biggest impact)
- Then optimize slow queries
- Finally tune memory usage
-
Learn from Guidance
- Read educational messages
- Follow fix suggestions
- Check documentation links
-
Set Realistic Thresholds
- Start with defaults
- Adjust based on actual requirements
- Consider operation complexity
# Mercury shows issues even when tests pass
# This is intentional - investigation mode discovers problems# Reduce verbosity
cls.configure_mercury(
verbose_reporting=False, # Less output
educational_guidance=False # Skip education
)# Adjust thresholds for complex operations
def test_complex_aggregation(self):
self.set_test_performance_thresholds({
'response_time_ms': 1000,
'query_count_max': 100
})- DjangoPerformanceAPITestCase - Production test case
- Performance Metrics - Understanding metrics
- Workflow Best Practices - Two-phase workflow
- Understanding Reports - Reading Mercury output