2010-10-14 07:25:09 +08:00
2011-03-04 06:40:38 +08:00
The writing and reporting of assertions in tests
==================================================
2010-10-14 07:25:09 +08:00
2012-06-17 16:59:30 +08:00
.. _`assertfeedback`:
2010-11-25 19:11:10 +08:00
.. _`assert with the assert statement`:
2012-10-12 20:52:36 +08:00
.. _`assert`:
2010-11-25 19:11:10 +08:00
2011-09-06 17:43:42 +08:00
Asserting with the ``assert`` statement
2010-10-14 07:25:09 +08:00
---------------------------------------------------------
2014-01-18 19:31:33 +08:00
``pytest`` allows you to use the standard python ``assert`` for verifying
2010-10-14 07:25:09 +08:00
expectations and values in Python tests. For example, you can write the
2011-03-04 06:40:38 +08:00
following::
2010-10-14 07:25:09 +08:00
# content of test_assert1.py
def f():
return 3
def test_function():
assert f() == 4
2011-05-28 01:30:27 +08:00
to assert that your function returns a certain value. If this assertion fails
2011-06-19 04:30:46 +08:00
you will see the return value of the function call::
2010-10-14 07:25:09 +08:00
$ py.test test_assert1.py
2011-08-21 00:37:00 +08:00
=========================== test session starts ============================
2014-09-24 20:46:56 +08:00
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
2012-10-07 19:06:17 +08:00
collected 1 items
2014-01-29 20:47:11 +08:00
2010-10-14 07:25:09 +08:00
test_assert1.py F
2014-01-29 20:47:11 +08:00
2011-08-21 00:37:00 +08:00
================================= FAILURES =================================
______________________________ test_function _______________________________
2014-01-29 20:47:11 +08:00
2010-10-14 07:25:09 +08:00
def test_function():
> assert f() == 4
E assert 3 == 4
E + where 3 = f()
2014-01-29 20:47:11 +08:00
2010-10-14 07:25:09 +08:00
test_assert1.py:5: AssertionError
2012-10-07 19:06:17 +08:00
========================= 1 failed in 0.01 seconds =========================
2010-10-14 07:25:09 +08:00
2014-01-18 19:31:33 +08:00
``pytest`` has support for showing the values of the most common subexpressions
2011-06-19 04:30:46 +08:00
including calls, attributes, comparisons, and binary and unary
operators. (See :ref:`tbreportdemo`). This allows you to use the
idiomatic python constructs without boilerplate code while not losing
introspection information.
2011-05-28 01:30:27 +08:00
2011-06-19 04:30:46 +08:00
However, if you specify a message with the assertion like this::
2011-06-19 04:07:36 +08:00
2011-06-19 04:30:46 +08:00
assert a % 2 == 0, "value was odd, should be even"
then no assertion introspection takes places at all and the message
will be simply shown in the traceback.
2011-05-28 01:30:27 +08:00
2011-06-19 04:30:46 +08:00
See :ref:`assert-details` for more information on assertion introspection.
2011-03-04 06:40:38 +08:00
2012-10-09 20:35:17 +08:00
.. _`assertraises`:
2011-09-06 17:43:42 +08:00
Assertions about expected exceptions
2010-10-14 07:25:09 +08:00
------------------------------------------
In order to write assertions about raised exceptions, you can use
2010-11-18 05:12:16 +08:00
``pytest.raises`` as a context manager like this::
2010-10-14 07:25:09 +08:00
2011-03-04 06:40:38 +08:00
import pytest
2014-09-08 21:26:31 +08:00
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
2010-10-14 07:25:09 +08:00
and if you need to have access to the actual exception info you may use::
2014-09-08 21:26:31 +08:00
def test_recursion_depth():
with pytest.raises(RuntimeError) as excinfo:
def f():
f()
2010-10-14 07:25:09 +08:00
f()
2014-09-08 21:26:31 +08:00
assert 'maximum recursion' in str(excinfo.value)
2010-10-14 07:25:09 +08:00
2013-08-01 17:12:02 +08:00
``excinfo`` is a `py.code.ExceptionInfo`_ instance, which is a wrapper around
2014-09-08 21:26:31 +08:00
the actual exception raised. The main attributes of interest are
``.type``, ``.value`` and ``.traceback``.
2013-08-01 17:12:02 +08:00
.. _py.code.ExceptionInfo:
http://pylib.readthedocs.org/en/latest/code.html#py-code-exceptioninfo
2011-12-05 18:10:48 +08:00
If you want to write test code that works on Python 2.4 as well,
2010-10-14 07:25:09 +08:00
you may also use two other ways to test for an expected exception::
2010-11-18 05:12:16 +08:00
pytest.raises(ExpectedException, func, *args, **kwargs)
pytest.raises(ExpectedException, "func(*args, **kwargs)")
2010-10-14 07:25:09 +08:00
both of which execute the specified function with args and kwargs and
asserts that the given ``ExpectedException`` is raised. The reporter will
provide you with helpful output in case of failures such as *no
exception* or *wrong exception*.
2014-07-27 00:10:32 +08:00
Note that it is also possible to specify a "raises" argument to
``pytest.mark.xfail``, which checks that the test is failing in a more
specific way than just having any exception raised::
@pytest.mark.xfail(raises=IndexError)
def test_f():
f()
Using ``pytest.raises`` is likely to be better for cases where you are testing
exceptions your own code is deliberately raising, whereas using
``@pytest.mark.xfail`` with a check function is probably better for something
like documenting unfixed bugs (where the test describes what "should" happen)
or bugs in dependencies.
2010-11-26 03:06:42 +08:00
.. _newreport:
2010-10-14 07:25:09 +08:00
Making use of context-sensitive comparisons
-------------------------------------------------
.. versionadded:: 2.0
2014-01-18 19:31:33 +08:00
``pytest`` has rich support for providing context-sensitive information
2010-10-14 07:25:09 +08:00
when it encounters comparisons. For example::
# content of test_assert2.py
def test_set_comparison():
set1 = set("1308")
set2 = set("8035")
assert set1 == set2
if you run this module::
$ py.test test_assert2.py
2011-08-21 00:37:00 +08:00
=========================== test session starts ============================
2014-09-24 20:46:56 +08:00
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
2012-10-07 19:06:17 +08:00
collected 1 items
2014-01-29 20:47:11 +08:00
2010-10-14 07:25:09 +08:00
test_assert2.py F
2014-01-29 20:47:11 +08:00
2011-08-21 00:37:00 +08:00
================================= FAILURES =================================
___________________________ test_set_comparison ____________________________
2014-01-29 20:47:11 +08:00
2010-10-14 07:25:09 +08:00
def test_set_comparison():
set1 = set("1308")
set2 = set("8035")
> assert set1 == set2
E assert set(['0', '1', '3', '8']) == set(['0', '3', '5', '8'])
E Extra items in the left set:
E '1'
E Extra items in the right set:
E '5'
2014-01-29 20:47:11 +08:00
2010-10-14 07:25:09 +08:00
test_assert2.py:5: AssertionError
2012-10-07 19:06:17 +08:00
========================= 1 failed in 0.01 seconds =========================
2010-10-14 07:25:09 +08:00
Special comparisons are done for a number of cases:
* comparing long strings: a context diff is shown
* comparing long sequences: first failing indices
* comparing dicts: different entries
2010-11-26 03:06:42 +08:00
See the :ref:`reporting demo <tbreportdemo>` for many more examples.
2010-11-25 20:00:01 +08:00
2011-06-21 00:12:48 +08:00
Defining your own assertion comparison
----------------------------------------------
It is possible to add your own detailed explanations by implementing
the ``pytest_assertrepr_compare`` hook.
.. autofunction:: _pytest.hookspec.pytest_assertrepr_compare
As an example consider adding the following hook in a conftest.py which
provides an alternative explanation for ``Foo`` objects::
# content of conftest.py
from test_foocompare import Foo
def pytest_assertrepr_compare(op, left, right):
if isinstance(left, Foo) and isinstance(right, Foo) and op == "==":
return ['Comparing Foo instances:',
' vals: %s != %s' % (left.val, right.val)]
now, given this test module::
# content of test_foocompare.py
class Foo:
def __init__(self, val):
self.val = val
def test_compare():
f1 = Foo(1)
f2 = Foo(2)
assert f1 == f2
2014-01-18 19:31:33 +08:00
you can run the test module and get the custom output defined in
2011-06-21 00:12:48 +08:00
the conftest file::
$ py.test -q test_foocompare.py
F
2011-08-21 00:37:00 +08:00
================================= FAILURES =================================
_______________________________ test_compare _______________________________
2014-01-18 19:31:33 +08:00
2011-06-21 00:12:48 +08:00
def test_compare():
f1 = Foo(1)
f2 = Foo(2)
> assert f1 == f2
E assert Comparing Foo instances:
E vals: 1 != 2
2014-01-18 19:31:33 +08:00
2011-06-21 00:12:48 +08:00
test_foocompare.py:8: AssertionError
2013-10-04 01:09:18 +08:00
1 failed in 0.01 seconds
2011-05-27 10:08:55 +08:00
2011-05-28 01:30:27 +08:00
.. _assert-details:
2011-06-15 13:50:34 +08:00
.. _`assert introspection`:
2011-05-28 01:30:27 +08:00
2011-06-15 13:50:34 +08:00
Advanced assertion introspection
----------------------------------
.. versionadded:: 2.1
2011-05-27 10:08:55 +08:00
2011-06-19 04:30:46 +08:00
Reporting details about a failing assertion is achieved either by rewriting
2011-05-27 10:08:55 +08:00
assert statements before they are run or re-evaluating the assert expression and
recording the intermediate values. Which technique is used depends on the
2014-01-18 19:31:33 +08:00
location of the assert, ``pytest`` configuration, and Python version being used
to run ``pytest``. Note that for assert statements with a manually provided
2011-06-29 23:52:39 +08:00
message, i.e. ``assert expr, message``, no assertion introspection takes place
and the manually provided message will be rendered in tracebacks.
2011-05-27 10:08:55 +08:00
2014-01-18 19:31:33 +08:00
By default, if the Python version is greater than or equal to 2.6, ``pytest``
2011-05-27 10:08:55 +08:00
rewrites assert statements in test modules. Rewritten assert statements put
2014-01-18 19:31:33 +08:00
introspection information into the assertion failure message. ``pytest`` only
2011-05-27 10:08:55 +08:00
rewrites test modules directly discovered by its test collection process, so
2011-06-29 23:52:39 +08:00
asserts in supporting modules which are not themselves test modules will not be
rewritten.
2011-05-27 10:08:55 +08:00
2011-05-29 08:00:47 +08:00
.. note::
2014-01-18 19:31:33 +08:00
``pytest`` rewrites test modules on import. It does this by using an import
hook to write a new pyc files. Most of the time this works transparently.
However, if you are messing with import yourself, the import hook may
interfere. If this is the case, simply use ``--assert=reinterp`` or
2011-07-05 23:29:53 +08:00
``--assert=plain``. Additionally, rewriting will fail silently if it cannot
2011-06-29 23:52:39 +08:00
write new pycs, i.e. in a read-only filesystem or a zipfile.
2011-05-29 08:00:47 +08:00
2011-05-27 10:08:55 +08:00
If an assert statement has not been rewritten or the Python version is less than
2014-01-18 19:31:33 +08:00
2.6, ``pytest`` falls back on assert reinterpretation. In assert
reinterpretation, ``pytest`` walks the frame of the function containing the
assert statement to discover sub-expression results of the failing assert
statement. You can force ``pytest`` to always use assertion reinterpretation by
passing the ``--assert=reinterp`` option.
2011-05-27 10:08:55 +08:00
Assert reinterpretation has a caveat not present with assert rewriting: If
evaluating the assert expression has side effects you may get a warning that the
intermediate values could not be determined safely. A common example of this
issue is an assertion which reads from a file::
assert f.read() != '...'
If this assertion fails then the re-evaluation will probably succeed!
This is because ``f.read()`` will return an empty string when it is
called the second time during the re-evaluation. However, it is
easy to rewrite the assertion and avoid any trouble::
content = f.read()
assert content != '...'
2011-07-05 23:29:53 +08:00
All assert introspection can be turned off by passing ``--assert=plain``.
2011-05-27 10:08:55 +08:00
2014-01-18 19:31:33 +08:00
For further information, Benjamin Peterson wrote up `Behind the scenes of pytest's new assertion rewriting <http://pybites.blogspot.com/2011/07/behind-scenes-of-pytests-new-assertion.html>`_.
2011-07-12 16:38:02 +08:00
2011-05-27 12:13:39 +08:00
.. versionadded:: 2.1
2011-05-29 05:01:02 +08:00
Add assert rewriting as an alternate introspection technique.
2011-05-27 12:13:39 +08:00
.. versionchanged:: 2.1
2011-07-05 23:29:53 +08:00
Introduce the ``--assert`` option. Deprecate ``--no-assert`` and
2011-05-27 12:13:39 +08:00
``--nomagic``.