All notable changes to phpunit-db-querycounter will be documented in this file
- Add Doctrine/Symfony and Phalcon support via a driver-based architecture, while keeping Laravel zero-config
- Unsupported features (lazy loading on Doctrine/Phalcon, query timing on Doctrine) now emit PHPUnit warnings instead of skipping the entire test
- Add CI matrix covering all three frameworks across PHP 8.2–8.4
Full Changelog: https://github.com/mattiasgeniar/phpunit-query-count-assertions/compare/1.2.4...1.2.5
- Support multiple connections by @mattiasgeniar in #17
Full Changelog: https://github.com/mattiasgeniar/phpunit-query-count-assertions/compare/1.2.2...1.2.4
Full Changelog: https://github.com/mattiasgeniar/phpunit-query-count-assertions/compare/1.2.1...1.2.3
- Consolidated
trackQueriesForEfficiency()intotrackQueries()— one method now does everything - Changed
trackQueries()from static to instance method for consistent$this->API
self::trackQueries() → $this->trackQueries()
The method is no longer static. Update your setUp/beforeEach:
// Before
protected function setUp(): void
{
parent::setUp();
self::trackQueries();
}
// After
protected function setUp(): void
{
parent::setUp();
$this->trackQueries();
}
trackQueriesForEfficiency() is deprecated
Replace with trackQueries():
// Before
$this->trackQueriesForEfficiency();
// After
$this->trackQueries();
Find and replace in your test files:
| Find | Replace |
|---|---|
self::trackQueries() |
$this->trackQueries() |
$this->trackQueriesForEfficiency() |
$this->trackQueries() |
The previous API had two methods that were confusingly similar:
trackQueries()— basic query loggingtrackQueriesForEfficiency()— query logging + N+1 detection
Now there's just one method that does everything. If you only need query counts, the efficiency tracking has zero overhead — just don't call assertQueriesAreEfficient().
- Multi-connection support:
trackQueries()now tracks queries across ALL database connections by default usingDB::listen(). Previously only the default connection was tracked. This fixes the issue where queries on named connections (like 'replica', 'read', 'write') were not captured. - New optional parameter to filter tracking to specific connections:
$this->trackQueries(); // Track all connections (new default) $this->trackQueries('replica'); // Track only 'replica' connection $this->trackQueries(['mysql', 'replica']); // Track multiple specific connections
- Tracked queries now include a
connectionkey indicating which connection executed each query.
- Breaking:
trackQueries()is now an instance method. Changeself::trackQueries()to$this->trackQueries(). - Breaking:
trackQueries()now tracks all connections by default instead of just the default connection. If you relied on the previous behavior of only tracking the default connection, pass the connection name explicitly:$this->trackQueries('mysql'). - Consolidated
trackQueriesForEfficiency()intotrackQueries(). The singletrackQueries()method now enables all tracking features including N+1/lazy loading detection.trackQueriesForEfficiency()is deprecated and will be removed in the next major version. - Lowered the default MySQL
minRowsForScanWarningthreshold to 10 (aligns with MySQL docs on tiny tables). - Emit INFO-level index analysis notices by default (non-failing) to surface suppressed index issues.
- Replaced per-connection query logging with a global
DB::listen()callback for more reliable cross-connection tracking. - Simplified internal implementation by removing redundant code and using modern PHP features (null coalescing assignment, typed properties).
- Fixed: Queries on non-default connections (e.g., 'replica') are now properly tracked (#16)
- Skip full index scan warnings for small tables (fewer than 10 rows) where MySQL optimizer prefers scans over seeks
- Skip unused index warnings for small tables where MySQL optimizer prefers full scans (fewer than 10 rows)
- Add query location reporting to assertion failures by @mattiasgeniar in #14
Full Changelog: https://github.com/mattiasgeniar/phpunit-query-count-assertions/compare/1.1.6...1.1.7
This release adds powerful query performance assertions to catch inefficient queries in your tests.
Detect full table scans and missing indexes by running EXPLAIN on your queries:
$this->assertAllQueriesUseIndexes(function () {
User::where('email', 'test@example.com')->first();
});
Supports MySQL, MariaDB, and SQLite. Detects full table scans, unused indexes, filesort, temporary tables, and more.
Catch repeated identical queries:
$this->assertNoDuplicateQueries(function () {
User::find(1);
User::find(1); // Fails - duplicate
});
Set performance budgets for your queries:
$this->assertMaxQueryTime(100, fn() => ...); // No single query over 100ms
$this->assertTotalQueryTime(500, fn() => ...); // Total time under 500ms
Fail when queries examine too many rows:
$this->assertMaxRowsExamined(1000, fn() => User::where('status', 'active')->get());
Check everything at once—N+1, duplicates, and index usage:
$this->assertQueriesAreEfficient(function () {
$users = User::with('posts')->get();
});
Or use trackQueries() in setUp/beforeEach for test-wide tracking.
Add support for additional databases:
AssertsQueryCounts::registerQueryAnalyser(new PostgresAnalyser());
- Issue severity levels (ERROR, WARNING, INFO) with configurable failure thresholds
- Small table optimization: ignores full scans on tables < 10 rows
- FK constraint context in SQLite scan warnings
- PHPStan analysis added to CI
Fully backwards compatible. All existing methods unchanged.
PHP 8.4 support
Support for Laravel 12
Support for Laravel 11.x added
- support Laravel 10
- support Laravel 9
- support Laravel 9
- initial release