This post briefly covers some tools for debugging failing tests when using pytest.
If looking at the traceback from a test failure isn’t enough there are a few tools to help debug a failing test:
-
The
--showlocalsargument to pytest will print out the values of all local variables after the traceback whenever a test fails. Sometimes this can be enough extra information to find the problem:$ tox -e py27-h tests/h -- --showlocals -
Pytest will capture the output of any Python
printstatements and print it after the traceback for the failing test. The output ofprintstatements in the test code or in the code under test is printed (but print statements from tests that passed are not printed).Add
printstatements to the tests and to the code under test to print out information that can help you to figure out what’s going wrong - the values of arguments and local variables, which lines of code are called (and in which order), etc.Just remember to delete the
prints again before committing the code!Tip: Try wrapping a
printstatement in anifclause, so that something is printed out only if some expression is true. This can be useful for only printing out the valuable information, and not a lot of noise, if theprintstatement needs to be on a line of code that’s executed many times during the test. -
The
--pdbargument to pytest will drop into a pdb debugger shell whenever a test fails, at the line of code that fails:$ tox -e py27-h tests/h -- --pdbFrom this shell you can inspect the values of variables and arguments, evaluate expressions, step through code one line at a time, etc. For some tips see pdb on pymotw.
-
ipdbis an enhanced debugger shell based on ipython, with syntax highlighting, tab completion, etc. To use it you first need to install ipdb into tox’s virtual environment:$ .tox/py27-h/bin/pip install robpol86-pytest-ipdbWe’re using
robpol86-pytest-ipdbbecause thepytest-ipdbpackage is broken.Then run the tests with the
--ipdbargument instead of--pdb:$ tox -e py27-h tests/h -- --ipdbThere are many more Python debuggers that you can try, for example pdb++ and pudb.
-
set_trace()lets you drop into a debugger shell on any line of code, whether in a test or in the code under test, rather than just when a test fails. Put this line anywhere in the Python code:import pdb; pdb.set_trace()and you’ll drop into pdb whenever execution hits that line.
For ipdb you would use
import ipdb; ipdb.set_trace().As with
printstatements, wrappingset_trace()lines inifstatements can be a useful trick.As with
printstatements, remember to delete theset_trace()lines again before committing the code. Fortunately you can easily grep the entire codebase forset_trace, since this should never appear in production code.