Download the PHP package mattiasgeniar/phpunit-query-count-assertions without Composer

On this page you can find all versions of the php package mattiasgeniar/phpunit-query-count-assertions. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package phpunit-query-count-assertions

PHP query count assertions for PHPUnit

Latest Version on Packagist Total Downloads Tests PHP Version

Count and assert SQL queries in your tests. Catch N+1 problems, full table scans, duplicate queries, and slow queries before they hit production.

Supports Laravel, Doctrine/Symfony, and Phalcon.

Requirements

Driver Compatibility

Feature Laravel Doctrine Phalcon
Query counting
Query timing
Duplicate detection
Index analysis (EXPLAIN)
Row count analysis
Lazy loading detection

Note: Lazy loading detection requires framework-specific hooks that only Laravel provides. Assertions like assertNoLazyLoading() will emit a warning on Doctrine and Phalcon and pass without checking, since violations cannot be detected.

Note: Doctrine's logging middleware only fires before query execution, so query timing is not available. Timing assertions (assertMaxQueryTime, assertTotalQueryTime) will emit a warning and pass without checking for Doctrine.

Installation

You can install the package via composer:

Quick start

Add the trait, wrap your core logic with efficiency tracking:

This catches N+1 queries, duplicate queries, and missing indexes in a single assertion. Your test setup (factories, seeders) stays outside the tracked block so it doesn't trigger false positives.

Framework Setup

Laravel (auto-detected)

No configuration needed. The package auto-detects Laravel and uses DB::listen() for query tracking.

Symfony

Symfony requires the logging middleware to be registered as a service. Add this to config/packages/test/services.yaml (this directory is only loaded when APP_ENV=test, so the middleware won't affect dev or production):

Then in your tests:

Phalcon

What it catches

When something fails, you get actionable output with the exact queries and their locations (file:line).

Query count assertions

For cases where you need precise control over query counts:

Tracking queries across the entire test

If you need to count queries outside closures, initialize tracking in setUp():

Multi-connection support

By default, trackQueries() captures queries from all database connections — not just the default one. This is useful when your application uses read replicas, separate analytics databases, or tenant-specific connections.

Filtering to specific connections

You can optionally filter to only track specific connection(s):

This is useful when:

Failure messages

Failed assertions show you the actual queries:

Locations (file:line) are shown for each query when available. This applies to duplicate, index, row count, timing, and total time failures too.

Lazy loading / N+1 detection

Uses Laravel's built-in lazy loading prevention:

Output:

Note: Laravel only triggers this when loading multiple models. Single model fetches won't trigger violations.

Index usage / full table scan detection

Runs EXPLAIN on each query to detect performance issues:

Output:

Supported databases

Other databases will emit a warning and pass without checking. See Custom analysers to add support for additional databases.

What gets analyzed

Only queries that support EXPLAIN are analyzed:

Plain INSERT, CREATE, DROP, and other DDL statements are skipped.

Issue severity levels

Issues are classified by severity and shown with prefixes in the output:

Severity Prefix Meaning
Error [ERROR] Critical issues that almost always need fixing (full table scans, unused available indexes)
Warning [WARNING] Potential issues that may be acceptable in some cases (filesort, temporary tables, full index scans)
Info [INFO] Informational notes (low filter efficiency, co-routine usage)

By default, only errors and warnings cause assertion failures. Informational issues are printed as [INFO] notices (non-failing) so they're visible even when tests pass.

MySQL / MariaDB detects

SQLite detects

Small table optimization

Full table scans, full index scans, and "index available but not used" warnings on tables with fewer than 10 rows are ignored by default, since scanning tiny tables is often faster than using an index. MySQL's docs note this is common for tables with fewer than 10 rows: https://dev.mysql.com/doc/refman/8.4/en/table-scan-avoidance.html. See Configurable thresholds to adjust this.

Duplicate query detection

Same query executed multiple times? You'll know:

Output:

Note: Different bindings = different queries. User::find(1) and User::find(2) are unique.

Row count threshold (MySQL / MariaDB only)

Output:

SQLite doesn't provide row estimates in EXPLAIN QUERY PLAN, so a warning is emitted and the assertion passes without checking.

Query timing assertions

Output:

Combined efficiency assertion

assertQueriesAreEfficient() checks everything at once: N+1, duplicates, and missing indexes. The Quick start shows the recommended inline pattern. Below are alternative approaches.

With a closure

Pest: beforeEach()

PHPUnit: setUp()

Paranoid mode (automatic checks on every test)

Want to automatically check every test for query efficiency issues? You can use afterEach() hooks to run assertions globally. This is aggressive and may surface many issues - use with caution.

Pest (in tests/Pest.php):

PHPUnit (base test class):

This will fail any test that has N+1 queries, duplicate queries, or missing indexes. Consider starting with a subset of tests rather than your entire suite.

Opting out with #[DisableQueryTracking]

In paranoid mode, some tests may need to opt out — for example, tests with heavy seeders, migrations, or tests that intentionally execute many queries. Use the #[DisableQueryTracking] attribute to skip tracking for specific tests or entire classes:

You can also disable tracking for an entire test class:

When #[DisableQueryTracking] is present, trackQueries() returns early without setting up listeners, and all assertions (assertQueriesAreEfficient(), assertQueryCountMatches(), etc.) pass silently.

Configurable thresholds

MySQL analyser options

The MySQL analyser has configurable thresholds that can be set by registering a customized instance:

Method Default Description
withMinRowsForScanWarning(int) 10 Minimum rows to flag full table scans, full index scans, and unused index warnings
withMaxCost(float) null (disabled) Maximum query cost before flagging as a warning

Custom analysers

Add support for additional databases by implementing the QueryAnalyser interface:

Register your custom analyser in your test's setUp():

Custom analysers are checked before the built-in MySQL and SQLite analysers.

Helper methods

These methods let you inspect query data for custom assertions or debugging:

Testing

License

The MIT License (MIT). Please see License File for more information.


All versions of phpunit-query-count-assertions with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package mattiasgeniar/phpunit-query-count-assertions contains the following files

Loading the files please wait ...