test_ok1/doc/en/cache.rst

272 lines
8.0 KiB
ReStructuredText
Raw Normal View History

cache: working with cross-testrun state
=======================================
2015-08-18 01:17:39 +08:00
.. versionadded:: 2.8
.. warning::
2015-09-16 23:15:31 +08:00
The functionality of this core plugin was previosuly distributed
as a third party plugin named ``pytest-cache``. The core plugin
is compatible regarding command line options and API usage except that you
can only store/receive data between test runs that is json-serializable.
Usage
---------
The plugin provides two command line options to rerun failures from the
last ``py.test`` invocation:
* ``--lf`` (last failures) - to only re-run the failures.
* ``--ff`` (failures first) - to run the failures first and then the rest of
the tests.
For cleanup (usually not needed), a ``--cache-clear`` option allows to remove
all cross-session cache contents ahead of a test run.
Other plugins may access the `config.cache`_ object to set/get
**json encodable** values between ``py.test`` invocations.
Rerunning only failures or failures first
-----------------------------------------------
First, let's create 50 test invocation of which only 2 fail::
# content of test_50.py
import pytest
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
pytest.fail("bad luck")
If you run this for the first time you will see two failures::
$ py.test -q
.................F.......F........................
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
2 failed, 48 passed in 0.04 seconds
2015-09-17 02:44:41 +08:00
If you then run it with ``--lf``::
$ py.test --lf
=========================== test session starts ============================
2015-09-17 03:06:44 +08:00
platform linux2 -- Python 2.7.6, pytest-2.7.3.dev428+ng79d22bf.d20150916, py-1.4.30, pluggy-0.3.0
run-last-failure: rerun last 2 failures
2015-09-17 03:06:44 +08:00
rootdir: /tmp/doc-exec-94, inifile:
collected 50 items
test_50.py FF
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
2015-09-17 03:06:44 +08:00
================= 2 failed, 48 deselected in 0.01 seconds ==================
2015-09-17 02:44:41 +08:00
You have run only the two failing test from the last run, while 48 tests have
not been run ("deselected").
2015-09-17 02:44:41 +08:00
Now, if you run with the ``--ff`` option, all tests will be run but the first
previous failures will be executed first (as can be seen from the series
of ``FF`` and dots)::
$ py.test --ff
=========================== test session starts ============================
2015-09-17 03:06:44 +08:00
platform linux2 -- Python 2.7.6, pytest-2.7.3.dev428+ng79d22bf.d20150916, py-1.4.30, pluggy-0.3.0
run-last-failure: rerun last 2 failures first
2015-09-17 03:06:44 +08:00
rootdir: /tmp/doc-exec-94, inifile:
collected 50 items
test_50.py FF................................................
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
2015-09-17 03:06:44 +08:00
=================== 2 failed, 48 passed in 0.03 seconds ====================
.. _`config.cache`:
The new config.cache object
--------------------------------
.. regendoc:wipe
2015-09-17 03:06:44 +08:00
Plugins or conftest.py support code can get a cached value using the
pytest ``config`` object. Here is a basic example plugin which
implements a :ref:`fixture` which re-uses previously created state
across py.test invocations::
# content of test_caching.py
2015-09-17 03:06:44 +08:00
import pytest
import time
2015-09-17 03:06:44 +08:00
@pytest.fixture
def mydata(request):
val = request.config.cache.get("example/value", None)
if val is None:
time.sleep(9*0.6) # expensive computation :)
val = 42
request.config.cache.set("example/value", val)
return val
def test_function(mydata):
assert mydata == 23
If you run this command once, it will take a while because
of the sleep::
$ py.test -q
F
================================= FAILURES =================================
______________________________ test_function _______________________________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
2015-09-17 03:06:44 +08:00
test_caching.py:14: AssertionError
1 failed in 5.41 seconds
If you run it a second time the value will be retrieved from
the cache and this will be quick::
$ py.test -q
F
================================= FAILURES =================================
______________________________ test_function _______________________________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
2015-09-17 03:06:44 +08:00
test_caching.py:14: AssertionError
1 failed in 0.01 seconds
2015-09-16 23:15:31 +08:00
See the `cache-api`_ for more details.
Inspecting Cache content
-------------------------------
You can always peek at the content of the cache using the
``--cache-clear`` command line option::
$ py.test --cache-clear
=========================== test session starts ============================
2015-09-17 03:06:44 +08:00
platform linux2 -- Python 2.7.6, pytest-2.7.3.dev428+ng79d22bf.d20150916, py-1.4.30, pluggy-0.3.0
rootdir: /tmp/doc-exec-94, inifile:
collected 1 items
test_caching.py F
================================= FAILURES =================================
______________________________ test_function _______________________________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
2015-09-17 03:06:44 +08:00
test_caching.py:14: AssertionError
========================= 1 failed in 5.41 seconds =========================
Clearing Cache content
-------------------------------
You can instruct pytest to clear all cache files and values
by adding the ``--cache-clear`` option like this::
py.test --cache-clear
This is recommended for invocations from Continous Integration
servers where isolation and correctness is more important
than speed.
2015-09-16 23:15:31 +08:00
.. _`cache-api`:
config.cache API
========================================
The `config.cache`` object allows other plugins,
including ``conftest.py`` files,
to safely and flexibly store and retrieve values across
test runs because the ``config`` object is available
in many places.
Under the hood, the cache plugin uses the simple
dumps/loads API of the json stdlib module
2015-08-18 01:17:39 +08:00
.. currentmodule:: _pytest.cacheprovider
.. automethod:: Cache.get
.. automethod:: Cache.set
.. automethod:: Cache.makedir