mattiasgeniar/phpunit-query-count-assertions
Add PHPUnit/Pest assertions to count and analyze SQL queries in tests. Catch N+1 issues, duplicate queries, slow queries, missing indexes (EXPLAIN), row count problems, and Laravel lazy loading. Supports Laravel 11/12, Doctrine DBAL 4, and Phalcon 6+.
composer require --dev mattiasgeniar/phpunit-query-count-assertions.QueryCountAssertionsTrait (or extend the provided base test case if available).assertQueryCount() or assertMaxQueryCount() to validate query behavior.
public function test_loads_users_without_n_plus_one()
{
$user = User::factory()->create();
$post = Post::factory()->for($user)->create();
$this->assertMaxQueryCount(2, function () use ($post) {
$post->user; // Should be cached/fetched in 1 query, not 2 (N+1)
});
}
assertQueryCount($expected) for exact counts (e.g., "this endpoint should hit the DB exactly 3 times").assertMaxQueryCount($max) for fragile or variable operations (e.g., caching layers), allowing wiggle room while still catching regressions.assertQueryCountRange($min, $max) for operations with conditional branching (e.g., “5–7 queries depending on config”).RefreshDatabase trait—reset DB state between tests to avoid count drift due to seed data differences.dump() or logging) before asserting. Small changes (like logging or event listeners) may add queries—adjust budgets accordingly.Cache::flush() guards.DB::enableQueryLog() is auto-enabled by the trait; Doctrine users may need to register a logger).QueryCount::getCounts() or enable verbose output to see where extra queries occurred (the trait usually logs the full stack or query list on failure).queryLogResolver() in your test base class to plug into custom logging layers (e.g., Monolog-integrated DB loggers).SELECT @@version) via ignoreQueries() if supported—check the trait’s config options.How can I help you explore Laravel packages today?