Skip to content

DjangoMercuryAPITestCase

smattymatty edited this page Aug 27, 2025 · 1 revision

DjangoMercuryAPITestCase

The investigation test case for discovering performance issues in Django applications. This class provides automatic performance monitoring, intelligent threshold management, and educational guidance.

Overview

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.

Key Features

  • 🔍 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)

Quick Start

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

Class Attributes

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

Methods

Configuration Methods

configure_mercury()

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_performance_thresholds()

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_test_performance_thresholds()

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)

Context Managers

mercury_override_thresholds

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)

Assertion Methods

assert_mercury_performance_excellent()

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 needed

assert_mercury_performance_production_ready()

Assert that performance is ready for production deployment.

def assert_mercury_performance_production_ready(
    self,
    metrics: EnhancedPerformanceMetrics_Python
)

Operation Profiles

Mercury automatically detects operation types and applies appropriate thresholds:

Detected Operations

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

Intelligent Threshold Adjustment

Mercury adjusts thresholds based on context:

# Automatically detected from test code:
- Page size (pagination)
- Relation includes (select_related/prefetch_related)
- Search complexity
- Operation type

Educational Features

Performance Issue Detection

Mercury detects and explains common issues:

  1. N+1 Queries

    • Severity levels: LOW, MEDIUM, HIGH, SEVERE, CRITICAL
    • Provides specific fix suggestions
    • Shows which models are affected
  2. Slow Response Times

    • Identifies bottlenecks
    • Suggests optimization strategies
    • Recommends caching approaches
  3. High Memory Usage

    • Tracks memory overhead
    • Identifies memory leaks
    • Suggests efficient data structures

Educational Guidance Format

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/

Workflow Integration

Investigation Phase (This Class)

# 1. Use DjangoMercuryAPITestCase for discovery
class InvestigationTests(DjangoMercuryAPITestCase):
    def test_user_api(self):
        response = self.client.get('/api/users/')
        # Mercury discovers issues automatically

Output:

🔍 test_user_list: N+1 Query Pattern (HIGH)
   → Fix: Use select_related('profile')

Documentation Phase (Next Step)

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)

Test Summary

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

Configuration Examples

Basic Setup

class MyTests(DjangoMercuryAPITestCase):
    def test_api(self):
        response = self.client.get('/api/endpoint/')
        # Automatic monitoring with defaults

Custom Thresholds

class MyTests(DjangoMercuryAPITestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.set_performance_thresholds({
            'response_time_ms': 100,
            'query_count_max': 10
        })

Per-Test Override

def test_special_case(self):
    self.set_test_performance_thresholds({
        'response_time_ms': 500
    })
    # This test allows 500ms response time

Inline Override

def test_with_context(self):
    with self.mercury_override_thresholds({'query_count_max': 50}):
        # This block allows 50 queries
        response = self.client.get('/api/complex/')

Best Practices

  1. Use for Investigation Only

    • This class is for discovering issues
    • Don't use in CI/CD pipelines
    • Switch to DjangoPerformanceAPITestCase for production
  2. Fix Issues Systematically

    • Address N+1 queries first (biggest impact)
    • Then optimize slow queries
    • Finally tune memory usage
  3. Learn from Guidance

    • Read educational messages
    • Follow fix suggestions
    • Check documentation links
  4. Set Realistic Thresholds

    • Start with defaults
    • Adjust based on actual requirements
    • Consider operation complexity

Common Issues and Solutions

Issue: Tests Pass But Show Poor Performance

# Mercury shows issues even when tests pass
# This is intentional - investigation mode discovers problems

Issue: Too Many Warnings

# Reduce verbosity
cls.configure_mercury(
    verbose_reporting=False,  # Less output
    educational_guidance=False  # Skip education
)

Issue: False Positives for Complex Operations

# Adjust thresholds for complex operations
def test_complex_aggregation(self):
    self.set_test_performance_thresholds({
        'response_time_ms': 1000,
        'query_count_max': 100
    })

See Also

Django Mercury Wiki

🏠 Overview

Clone this wiki locally