Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpunit Query Count Assertions Laravel Package

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+.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install via Composer: composer require --dev mattiasgeniar/phpunit-query-count-assertions.
  2. Extend your test class with QueryCountAssertionsTrait (or extend the provided base test case if available).
  3. Start asserting: Wrap the code under test with 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)
        });
    }
    
  4. First use case: Catch N+1 in Eloquent/Doctrine queries—e.g., after creating related models, verify that accessing relationships doesn’t trigger extra queries.

Implementation Patterns

  • Per-test budgets: Use assertQueryCount($expected) for exact counts (e.g., "this endpoint should hit the DB exactly 3 times").
  • Soft boundaries: Prefer assertMaxQueryCount($max) for fragile or variable operations (e.g., caching layers), allowing wiggle room while still catching regressions.
  • Ranged assertions: Use assertQueryCountRange($min, $max) for operations with conditional branching (e.g., “5–7 queries depending on config”).
  • CI enforcement: Add these assertions to API controller tests, job handlers, or service classes to fail builds when query count spikes (e.g., after refactoring).
  • Integration with Laravel: Pair with RefreshDatabase trait—reset DB state between tests to avoid count drift due to seed data differences.

Gotchas and Tips

  • Trusted baseline matters: Record the current query count first (e.g., with dump() or logging) before asserting. Small changes (like logging or event listeners) may add queries—adjust budgets accordingly.
  • False positives: Avoid asserting counts around cached/redis-backed code—DB queries might not fire at all, or vary based on cache warm-up. Wrap such tests in Cache::flush() guards.
  • Driver compatibility: Ensure your DB layer supports query logging (e.g., Laravel’s DB::enableQueryLog() is auto-enabled by the trait; Doctrine users may need to register a logger).
  • Debugging: Use QueryCount::getCounts() or enable verbose output to see where extra queries occurred (the trait usually logs the full stack or query list on failure).
  • Extensibility: Override queryLogResolver() in your test base class to plug into custom logging layers (e.g., Monolog-integrated DB loggers).
  • Flaky tests? Exclude time-sensitive or non-deterministic queries (like SELECT @@version) via ignoreQueries() if supported—check the trait’s config options.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport