summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/pytest/doc/en/assert.rst
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/tools/pytest/doc/en/assert.rst')
-rw-r--r--testing/web-platform/tests/tools/pytest/doc/en/assert.rst289
1 files changed, 289 insertions, 0 deletions
diff --git a/testing/web-platform/tests/tools/pytest/doc/en/assert.rst b/testing/web-platform/tests/tools/pytest/doc/en/assert.rst
new file mode 100644
index 000000000..e7f14e8bd
--- /dev/null
+++ b/testing/web-platform/tests/tools/pytest/doc/en/assert.rst
@@ -0,0 +1,289 @@
+
+The writing and reporting of assertions in tests
+==================================================
+
+.. _`assertfeedback`:
+.. _`assert with the assert statement`:
+.. _`assert`:
+
+
+Asserting with the ``assert`` statement
+---------------------------------------------------------
+
+``pytest`` allows you to use the standard python ``assert`` for verifying
+expectations and values in Python tests. For example, you can write the
+following::
+
+ # content of test_assert1.py
+ def f():
+ return 3
+
+ def test_function():
+ assert f() == 4
+
+to assert that your function returns a certain value. If this assertion fails
+you will see the return value of the function call::
+
+ $ py.test test_assert1.py
+ ======= test session starts ========
+ platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
+ rootdir: $REGENDOC_TMPDIR, inifile:
+ collected 1 items
+
+ test_assert1.py F
+
+ ======= FAILURES ========
+ _______ test_function ________
+
+ def test_function():
+ > assert f() == 4
+ E assert 3 == 4
+ E + where 3 = f()
+
+ test_assert1.py:5: AssertionError
+ ======= 1 failed in 0.12 seconds ========
+
+``pytest`` has support for showing the values of the most common subexpressions
+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.
+
+However, if you specify a message with the assertion like this::
+
+ 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.
+
+See :ref:`assert-details` for more information on assertion introspection.
+
+.. _`assertraises`:
+
+Assertions about expected exceptions
+------------------------------------------
+
+In order to write assertions about raised exceptions, you can use
+``pytest.raises`` as a context manager like this::
+
+ import pytest
+
+ def test_zero_division():
+ with pytest.raises(ZeroDivisionError):
+ 1 / 0
+
+and if you need to have access to the actual exception info you may use::
+
+ def test_recursion_depth():
+ with pytest.raises(RuntimeError) as excinfo:
+ def f():
+ f()
+ f()
+ assert 'maximum recursion' in str(excinfo.value)
+
+``excinfo`` is a ``ExceptionInfo`` instance, which is a wrapper around
+the actual exception raised. The main attributes of interest are
+``.type``, ``.value`` and ``.traceback``.
+
+If you want to write test code that works on Python 2.4 as well,
+you may also use two other ways to test for an expected exception::
+
+ pytest.raises(ExpectedException, func, *args, **kwargs)
+ pytest.raises(ExpectedException, "func(*args, **kwargs)")
+
+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*.
+
+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.
+
+
+.. _`assertwarns`:
+
+Assertions about expected warnings
+-----------------------------------------
+
+.. versionadded:: 2.8
+
+You can check that code raises a particular warning using
+:ref:`pytest.warns <warns>`.
+
+
+.. _newreport:
+
+Making use of context-sensitive comparisons
+-------------------------------------------------
+
+.. versionadded:: 2.0
+
+``pytest`` has rich support for providing context-sensitive information
+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
+ ======= test session starts ========
+ platform linux -- Python 3.4.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
+ rootdir: $REGENDOC_TMPDIR, inifile:
+ collected 1 items
+
+ test_assert2.py F
+
+ ======= FAILURES ========
+ _______ test_set_comparison ________
+
+ 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'
+ E Use -v to get the full diff
+
+ test_assert2.py:5: AssertionError
+ ======= 1 failed in 0.12 seconds ========
+
+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
+
+See the :ref:`reporting demo <tbreportdemo>` for many more examples.
+
+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 __eq__(self, other):
+ return self.val == other.val
+
+ def test_compare():
+ f1 = Foo(1)
+ f2 = Foo(2)
+ assert f1 == f2
+
+you can run the test module and get the custom output defined in
+the conftest file::
+
+ $ py.test -q test_foocompare.py
+ F
+ ======= FAILURES ========
+ _______ test_compare ________
+
+ def test_compare():
+ f1 = Foo(1)
+ f2 = Foo(2)
+ > assert f1 == f2
+ E assert Comparing Foo instances:
+ E vals: 1 != 2
+
+ test_foocompare.py:11: AssertionError
+ 1 failed in 0.12 seconds
+
+.. _assert-details:
+.. _`assert introspection`:
+
+Advanced assertion introspection
+----------------------------------
+
+.. versionadded:: 2.1
+
+
+Reporting details about a failing assertion is achieved either by rewriting
+assert statements before they are run or re-evaluating the assert expression and
+recording the intermediate values. Which technique is used depends on the
+location of the assert, ``pytest`` configuration, and Python version being used
+to run ``pytest``.
+
+By default, ``pytest`` rewrites assert statements in test modules.
+Rewritten assert statements put introspection information into the assertion failure message.
+``pytest`` only rewrites test modules directly discovered by its test collection process, so
+asserts in supporting modules which are not themselves test modules will not be
+rewritten.
+
+.. note::
+
+ ``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
+ ``--assert=plain``. Additionally, rewriting will fail silently if it cannot
+ write new pycs, i.e. in a read-only filesystem or a zipfile.
+
+If an assert statement has not been rewritten or the Python version is less than
+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.
+
+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 != '...'
+
+All assert introspection can be turned off by passing ``--assert=plain``.
+
+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>`_.
+
+.. versionadded:: 2.1
+ Add assert rewriting as an alternate introspection technique.
+
+.. versionchanged:: 2.1
+ Introduce the ``--assert`` option. Deprecate ``--no-assert`` and
+ ``--nomagic``.