Adds the ability to retry flaky tests in CI environments
Project description
pytest-retry
pytest-retry is a plugin for Pytest which adds the ability to retry flaky tests, thereby improving the consistency of the test suite results.
Requirements
pytest-retry is designed for the latest versions of Python and Pytest. Python 3.9+ and pytest 7.0.0 are required.
Installation
Use pip to install pytest-retry:
$ pip install pytest-retry
Usage
There are two main ways to use pytest-retry:
1. Command line
Run Pytest with the command line argument --retries in order to retry every test in the event of a failure. The following example will retry each failed up to two times before proceeding to the next test:
$ python -m pytest --retries 2
An optional delay can be specified using the --retry-delay argument. This will insert a fixed delay (in seconds) between each attempt when a test fails. This can be useful if the test failures are due to intermittent environment issues which clear up after a few seconds
$ python -m pytest --retries 2 --retry-delay 5
2. Pytest flaky mark
Mark individual tests as 'flaky' to retry them when they fail. If no command line arguments are passed, only the marked tests will be retried. The default values are 1 retry attempt with a 0-second delay
@pytest.mark.flaky
def test_unreliable_service():
...
The number of times each test will be retried and/or the delay can be manually specified as well
@pytest.mark.flaky(retries=3, delay=1)
def test_unreliable_service():
...
Finally, there is both a command line option and flaky mark argument for the test
timing method, which can either be overwrite
(default) or cumulative
. With
cumulative timing, the duration of each test attempt is summed for the overall test
duration reported at the end. The default behavior simply uses the timing for
the final attempt.
@pytest.mark.flaky(timing='overwrite')
def test_unreliable_service():
...
If you're not sure which to use, stick with the default overwrite
method. This
generally plays nicer with time-based test splitting algorithms and will result in
more even splits.
The flaky mark will override any command line options if passed when running Pytest.
Things to consider
-
Currently, failing test fixtures are not retried. In the future, flaky test setup may be retried, although given the undesirability of flaky tests in general, flaky setup should be avoided at all costs. Any failures during teardown will immediately halt further attempts so that they can be addressed immediately. Make sure your teardowns always work reliably regardless of the number of retries when using this plugin
-
When a flaky test is retried, the plugin runs teardown steps for the test as if it had passed. This is to ensure that any partial state created by the test is cleaned up before the next attempt so that subsequent attempts do not conflict with one another. Class and module fixtures are included in this teardown with the assumption that false test failures should be a rare occurrence and the performance hit from re-running these potentially expensive fixtures is worth it to ensure clean initial test state. With feedback, the option to not re-run class and module fixtures may be added, but in general, these types of fixtures should be avoided for known flaky tests.
-
Flaky tests are not sustainable. This plugin is designed as an easy short-term solution while a permanent fix is implemented. Use the reports generated by this plugin to identify issues with the tests or testing environment and resolve them.
Reporting
pytest-retry intercepts the standard Pytest report flow in order to retry tests and update the reports as required. When a test is retried at least once, an R is printed to the live test output and the counter of retried tests is incremented by 1. After the test session has completed, an additional report is generated below the standard output which lists all of the tests which were retried, along with the exceptions that occurred during each failed attempt.
plugins: retry-1.1.0
collected 1 item
test_retry_passes_after_temporary_test_failure.py R. [100%]
======================= the following tests were retried =======================
test_eventually_passes failed on attempt 1! Retrying!
Traceback (most recent call last):
File "tests/test_example.py", line 4, in test_eventually_passes
assert len(a) > 1
AssertionError: assert 1 > 1
+ where 1 = len([1])
=========================== end of test retry report ===========================
========================= 1 passed, 1 retried in 0.01s =========================
Tests which have been retried but eventually pass are counted as both retried and passed, and tests which have been retried but eventually fail are counted as both retried and failed. Skipped, xfailed, and xpassed tests are never retried.
Two pytest stash keys are available to import from the pytest_retry plugin:
attempts_key
and success_key
. These keys are used by the plugin to store the
number of attempts each item has undergone and whether or not the test passed or
failed, respectively. (If any stage of setup, call, or teardown fails, a test is
considered failed overall). These stash keys can be used to retreive these reports
for use in your own hooks or plugins.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pytest-retry-1.1.0.tar.gz
.
File metadata
- Download URL: pytest-retry-1.1.0.tar.gz
- Upload date:
- Size: 10.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.10.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a05eb7070a7ea4a5761741894f36c40430443bc3046ad1362ef425533b70cef8 |
|
MD5 | cf99f7679fe087225d95acea420ab7ae |
|
BLAKE2b-256 | d2ac3a0b60772062c87aa7234c700c4e8482d88c44864fb1fafdcb056f63267c |
File details
Details for the file pytest_retry-1.1.0-py3-none-any.whl
.
File metadata
- Download URL: pytest_retry-1.1.0-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.10.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a33c1fb926327092bd89300a75eac362c073a99277085cbc375480fc6a937932 |
|
MD5 | 9260210aa3efbe06d057c0e50f2a709e |
|
BLAKE2b-256 | 7d1f4035f4662bf39ce8abc655c3790e57e9d6f206f50ca5c555ef02adc669f0 |