Blackfire gathers a lot of data about how your code behaves at runtime,
from wall-clock time, to I/O time or CPU time, memory, number of calls to a
given function, number of SQL queries and their execution time, and many other.
Some of these metrics are built-in, and you
can create your own as well.
Pretty much like writing unit tests or integration tests, Blackfire enables
you to write tests with these metrics. These can be performance tests,
which help you make sure your code sticks to a performance budget you have defined. And if
needed, such tests can go beyond performance, like our
quality and security recommendations.
Tests will be run on any profile you generate, may it be on-demand (like via the
or the CLI),
or automatically (like via the Blackfire Player
Test results will be displayed via the profile view (under the assertions tab on the
left-hand side), or aggregated in a Build report view.
The best way to get started with writing Blackfire tests is via the .blackfire.yaml
The .blackfire.yaml file is a YAML file where tests, metrics, and scenarios can be
defined. It must be part of your code repository:
"Pages should be fast enough":
path: "/.*" # run the assertions for all HTTP requests
- "main.wall_time < 100ms" # wall clock time is less than 100ms
"Commands should be fast enough":
command: ".*" # run the assertions for all CLI commands
- "main.wall_time < 2s" # wall clock time is less than 2s
To get started, create a .blackfire.yaml file in the root directory of an
application. You can bootstrap a new .blackfire.yaml file with the following
command: blackfire bootstrap-tests.
Use the online .blackfire.yaml validator
to validate the syntax of your .blackfire.yaml files.
Now that you have created the file, read the following paragraphs to learn more
about how to write your own tests.
A test must located under the tests key and is composed of the following
Here is an example with several assertions limited to some API calls of the
"Homepage should not hit the DB":
methods: [GET, HEAD]
- "metrics.sql.queries.count == 0" # no SQL statements executed
- "main.peak_memory < 10mb" # memory does not exceed 10mb
- "metrics.output.network_out < 100kb" # the response size is less than 100kb
When a profile is made on a project that contains a .blackfire.yaml file,
Blackfire automatically runs all tests matching the HTTP request path. The
result of the tests is displayed as a green or red icon in the dashboard and
the full report is available on the profile page. The same goes when
profiling a CLI script via blackfire run.
Note that assertions in the report contain the actual metric and variable
values so that you know if you are close to the target or not
(metrics.sql.queries.count 5 == 0; 0 is the target, 5 is the actual number
of SQL statements executed).
metrics.sql.queries.count 5 == 0
A condition is an expression similar to an assertion. If the condition is fulfilled, the test is
There are two kinds of conditions: when and unless.
They can be used separately or combined for a more complex conditions.
A when expression acts like an if condition. The corresponding test is
evaluated if the expression returns true.
'A database connection should be opened only when queries are made':
when: "metrics.sql.connections.count > 0"
- 'metrics.sql.queries.count > 0'
The example above means “For any HTTP request, if a database connection is
used, at least 1 SQL query must be run”.
An unless expression acts like an if not condition. The corresponding
test is evaluated unless the expression returns true.
'Twig template cache should be enabled in production':
- 'metrics.twig.compile.count == 0'
The example above means “For any HTTP request, unless the profile is run in
a development environment, Twig template path should be enabled”.
# A path or an array of paths, when in web context;
# Regular expression the web path must match to trigger the assertions.
# A path or an array of paths to exclude, when in web context;
# A command, when in CLI context;
# Regular expression the command must match to trigger the assertions.
command: bin/console project:cron
# A collection of HTTP Methods.
# Use ANY for accepting anything (it's the default value).
methods: # Example: [ GET, POST ]
# A condition. If not valid, the test will not be used.
when: ~ # Example: is_dev() == true
# A condition. If valid, the test will not be used.
unless: ~ # Example: is_dev() == true
# A collection of assertions
label: ~ # Example: No more than 5 SQL query
expression: ~ # Required, Example: metrics.sql.queries.count < 5