Gander Performance Testing
When to Use
Write Gander performance tests for modules with site-wide performance impact: event subscribers that fire on every request, cache invalidation logic, bulk operations, or features that execute complex queries.
Decision
| Module Type | Use Gander | Why |
|---|---|---|
| Event-driven modules (ECA, Rules) | Yes | Event cascades can cause performance issues |
| Page request processors | Yes | Affects every page load |
| Mass operations (imports, bulk updates) | Yes | Query count and cache impact matter |
| Cache invalidation logic | Yes | Wrong invalidation destroys performance |
| Simple CRUD operations | No | Standard database operations |
| Admin-only features | Maybe | Low usage frequency, less critical |
Pattern
<?php
namespace Drupal\Tests\my_module\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\PerformanceTestBase;
/**
* Tests the my_module performance characteristics.
*
* @group my_module
* @group Performance
* @group #slow
* @requires extension apcu
*/
class MyModulePerformanceTest extends PerformanceTestBase {
protected static $modules = ['my_module', 'node'];
protected $defaultTheme = 'stark';
protected $profile = 'minimal';
public function testFrontPagePerformanceImpact(): void {
// Measure cold cache performance
$performance_data = $this->collectPerformanceData(function() {
$this->drupalGet('<front>');
}, 'frontPageColdCache');
// Set performance expectations
$expected = [
'queryCount' => 50, // Maximum database queries
'cacheGetCount' => 20, // Maximum cache reads
'cacheSetCount' => 15, // Maximum cache writes
'cacheDeleteCount' => 0, // No cache deletes on normal request
'cacheTagChecksumCount' => 5, // Cache tag validations
];
$this->assertSame(200, $performance_data->getStatusCode());
$this->assertLessThanOrEqual($expected['queryCount'], $performance_data->getQueryCount());
$this->assertLessThanOrEqual($expected['cacheGetCount'], $performance_data->getCacheGetCount());
}
public function testHotCachePerformance(): void {
// Warm cache
$this->drupalGet('<front>');
sleep(1);
// Measure hot cache performance
$performance_data = $this->collectPerformanceData(function() {
$this->drupalGet('<front>');
}, 'frontPageHotCache');
// Expect minimal queries with warm cache
$this->assertLessThanOrEqual(10, $performance_data->getQueryCount());
$this->assertGreaterThan(5, $performance_data->getCacheGetCount());
}
public function testBulkOperationPerformance(): void {
// Create test content
$this->createNode(['type' => 'article', 'title' => 'Test']);
// Measure bulk processing
$performance_data = $this->collectPerformanceData(function() {
$service = \Drupal::service('my_module.bulk_processor');
// Process 100 items
for ($i = 0; $i < 100; $i++) {
$service->processItem(['id' => $i, 'data' => "test_$i"]);
}
}, 'bulkProcessing100Items');
// Assert reasonable performance bounds
$this->assertLessThanOrEqual(200, $performance_data->getQueryCount());
$this->assertLessThanOrEqual(50, $performance_data->getCacheSetCount());
// Ensure we're not invalidating too many caches
$this->assertLessThanOrEqual(10, $performance_data->getCacheTagInvalidationCount());
}
}
File Location: modules/my_module/tests/src/FunctionalJavascript/MyModulePerformanceTest.php
Note: Performance tests extend PerformanceTestBase (since Drupal 10.2) and use OpenTelemetry tracing.
Common Mistakes
- Wrong: Running performance tests without APCu enabled → Right: Enable APCu extension for accurate cache metrics
- Wrong: Not warming caches before hot cache tests → Right: Run request once, then measure second request
- Wrong: Setting unrealistic performance budgets → Right: Base budgets on actual measurements
- Wrong: Testing performance too early in development → Right: Add performance tests after features stabilize
- Wrong: Not comparing with/without module enabled → Right: Measure baseline to understand actual impact
See Also
- PHPUnit FunctionalJavascript Tests
- Progressive Testing Strategy
- Best Practices & Anti-Patterns
- Reference: Performance tests - Drupal.org
- Reference:
/core/tests/Drupal/FunctionalJavascriptTests/PerformanceTestBase.php