pytest-interactive: select tests to run using a REPL ==================================================== This plugin allows for the selection and run of ``pytest`` tests using the command line facilities available in `IPython `_. This includes tab completion along the ``pytest`` node hierarchy and test callspec ids as well as the use of standard Python subscript and slice syntax for selection. Upon invocation with either the ``--interactive`` or shorthand ``--ia`` arguments, you will enter an IPython shell which allows for navigation of the test tree built during the ``pytest`` collection phase. Enjoy and feel free to submit PRs, ask for features, or report bugs on the `github page`_. .. _github page: https://github.com/tgoodlet/pytest-interactive Quickstart ---------- To invoke the interactive plugin simply run pytest as normal from the top of your test tree like so .. code-block:: console $ py.test -vvvs --interactive example_test_set/ or more compactly .. code-block:: console $ py.test -vvvs --ia example_test_set/ Pytest will execute normally up until the end of the collection phase at which point it will enter a slightly customized ``IPython`` shell: :: ============================ test session starts ============================ platform linux -- Python 3.4.1 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python plugins: interactive collected 63 items Building test tree... Entering IPython shell... Welcome to pytest-interactive, the pytest + IPython sensation! Please explore the test (collection) tree using tt. When finished tabbing to a test node, simply __call__ it to have pytest invoke all tests collected under that node. .. code-block:: python '0' selected >>> '0' selected >>> tt. tt.test_pinky_strength tt.test_dogs_breath tt.test_manliness tt.test_cats_meow '0' selected >>> tt.testsdir.test_pinky_strength. tt.test_pinky_strength.test_contrived_name_0 tt.test_pinky_strength.test_the_readers_patience That's right, jacked pinky finger here you come... Select tests via tab-completion ----------------------------------- Basic tab completion should allow you to navigate to the test(s) of interest as well as aid in exploring the overall ``pytest`` collection tree. Tab completion works along python packages, modules, classes and test functions. The latter three types are collected as nodes by pytest out of the box but as an extra aid, intermediary nodes are created for packages containing tests as well. This is helpful to distinguish between different groups of tests in the file system. .. note:: The binding ``tt`` (abbreviation for *test tree*) is a reference to the root of a tree of nodes which roughly corresponds to the collection tree gathered by ``pytest``. If you'd like to see all tests included by a particular node simply evaluate it on the shell to trigger a pretty print ``__repr__()`` method: .. code-block:: python '0' selected >>> tt.tests.subsets.test_setA Out [0]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Total 15 tests When ready to run pytest, simply :func:`__call__()` the current node to exit the shell and invoke all tests below it in the tree: .. code-block:: python '0' selected >>> tt.test_setB.test_modes() :: example_test_set/tests/subsets/subsubset/test_setB.py::test_modes[a] example_test_set/tests/subsets/subsubset/test_setB.py::test_modes[b] example_test_set/tests/subsets/subsubset/test_setB.py::test_modes[c] You have selected the above 3 test(s) to be run. Would you like to run pytest now? ([y]/n)? example_test_set/tests/subsets/subsubset/test_setB.py:41: test_modes[a] PASSED example_test_set/tests/subsets/subsubset/test_setB.py:41: test_modes[b] PASSED example_test_set/tests/subsets/subsubset/test_setB.py:41: test_modes[c] FAILED Selection by index or slice --------------------------- Tests can also be selected by slice or subscript notation. This is handy if you see the test(s) you'd like to run in the pretty print output but don't feel like tab-completing all the way down the tree to the necessary leaf node. Take the following subtree of tests for example: .. code-block:: python '0' selected >>> tt.test_setB.test_modes Out[1]: 0 1 2 Total 3 tests Now let's select the last test .. code-block:: python '0' selected >>> tt.test_setB.test_modes[-1] Out[2]: 0 Total 1 tests Or how about the first two .. code-block:: python '0' selected >>> tt.test_setB.test_modes[:2] Out[52]: 0 1 Total 2 tests You can of course :func:`__call__()` the indexed node as well to immediately run all tests in the selection. Filtering by parameterized test callspec ids -------------------------------------------- Tests which are generated at runtime (aka parametrized) can be filtered by their callspec ids. Normally the ids are shown inside the braces ``[...]`` of the test *nodeid* which often looks something like: ```` (i.e. what you get for output when using the ``--collectonly`` arg) .. not sure why the params ref below doesn't link internally ... To access the available ids use the node's :py:attr:`~interactive.plugin.TestSet.params` attribute. .. code-block:: python '0' selected >>> tt.params. tt.params.a tt.params.b tt.params.c tt.params.cat tt.params.dog tt.params.mouse '0' selected >>> tt.params.a Out[2]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Total 16 tests You can continue to filter in this way as much as is possible .. code-block:: python '0' selected >>> tt.params.a.params. tt.params.a.params.cat tt.params.a.params.dog tt.params.a.params.mouse '0' selected >>> tt.params.a.params.mouse Out[3]: 0 Total 1 tests .. warning:: There is one stipulation with using id filtering which is that the id tokens must be valid python literals. Otherwise the :py:meth:`__getattr__` overloading of the node will not work. It is recomended that you give your parameterized tests tab completion friendly ids using the `ids kwarg`_ as documented on the pytest site. .. _ids kwarg: http://pytest.org/latest/parametrize.html #_pytest.python.Metafunc.parametrize Multiple selections and magics ------------------------------ So by now I'm sure you've thought *but what if I want to select tests from totally different parts of the tree?* Well lucky for you some %magics have been added to the shell to help with just that problem: .. code-block:: python '0' selected >>> tt.test_setB.test_modes Out[1]: 0 1 2 Total 3 tests '0' selected >>> add tt.test_setB.test_modes[-2:] '2' selected >>> You can easily show the contents of your selection .. code-block:: python '2' selected >>> show 0 1 '2' selected >>> You can also remove tests from the current selection by index .. code-block:: python '2' selected >>> remove 1 '1' selected >>> show 0 '1' selected >>> When ready to run your tests simply exit the shell .. code-block:: python '1' selected >>> exit For additional docs on the above shell %magics simply use the ``%?`` magic syntax available in the IPython shell (i.e. ``add?`` or ``remove?`` or ``show?``). ``lastfailed`` tests -------------------- ``pytest`` exposes the list of failed test from the most recent run and stores them in its `cache`_. Normally you can select only those test using the ``--lf`` flag. ``pytest-interactive`` always wraps the `last failed` test set in its shell's local namespace using under name ``lastfailed``. Using the ``pytest`` cache -------------------------- You can store test sets for access across sessions using the ``pytest`` `cache`_. A magic ``%cache`` is available for creating and deleting entries: .. code-block:: python '0' selected >>> cache add tt.test_setB.test_modes setb '0' selected >>> cache Summary: setb -> 3 items '0' selected >>> setb # the local namespace is auto-updated 0 1 2 '0' selected >>> exit # ... come back in a later session ... # the local namespace is auto-populated with cache entries '0' selected >>> setb 0 1 2 '0' selected >>> cache del setb Deleted cache entry for 'setb' See ``%cache?`` for full command details. API reference ------------- .. toctree:: :maxdepth: 2 plugin shell .. links .. _cache: http://doc.pytest.org/en/latest/cache.html