Asserting Warnings ===================================================== .. _warns: Asserting warnings with the warns function ----------------------------------------------- .. versionadded:: 2.8 You can check that code raises a particular warning using ``pytest.warns``, which works in a similar manner to :ref:`raises `:: import warnings import pytest def test_warning(): with pytest.warns(UserWarning): warnings.warn("my warning", UserWarning) The test will fail if the warning in question is not raised. You can also call ``pytest.warns`` on a function or code string:: pytest.warns(expected_warning, func, *args, **kwargs) pytest.warns(expected_warning, "func(*args, **kwargs)") The function also returns a list of all raised warnings (as ``warnings.WarningMessage`` objects), which you can query for additional information:: with pytest.warns(RuntimeWarning) as record: warnings.warn("another warning", RuntimeWarning) # check that only one warning was raised assert len(record) == 1 # check that the message matches assert record[0].message.args[0] == "another warning" Alternatively, you can examine raised warnings in detail using the :ref:`recwarn ` fixture (see below). .. note:: ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated differently; see :ref:`ensuring_function_triggers`. .. _recwarn: Recording warnings ------------------------ You can record raised warnings either using ``pytest.warns`` or with the ``recwarn`` fixture. To record with ``pytest.warns`` without asserting anything about the warnings, pass ``None`` as the expected warning type:: with pytest.warns(None) as record: warnings.warn("user", UserWarning) warnings.warn("runtime", RuntimeWarning) assert len(record) == 2 assert str(record[0].message) == "user" assert str(record[1].message) == "runtime" The ``recwarn`` fixture will record warnings for the whole function:: import warnings def test_hello(recwarn): warnings.warn("hello", UserWarning) assert len(recwarn) == 1 w = recwarn.pop(UserWarning) assert issubclass(w.category, UserWarning) assert str(w.message) == "hello" assert w.filename assert w.lineno Both ``recwarn`` and ``pytest.warns`` return the same interface for recorded warnings: a WarningsRecorder instance. To view the recorded warnings, you can iterate over this instance, call ``len`` on it to get the number of recorded warnings, or index into it to get a particular recorded warning. It also provides these methods: .. autoclass:: _pytest.recwarn.WarningsRecorder() :members: Each recorded warning has the attributes ``message``, ``category``, ``filename``, ``lineno``, ``file``, and ``line``. The ``category`` is the class of the warning. The ``message`` is the warning itself; calling ``str(message)`` will return the actual message of the warning. .. note:: ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated differently; see :ref:`ensuring_function_triggers`. .. _ensuring_function_triggers: Ensuring a function triggers a deprecation warning ------------------------------------------------------- You can also call a global helper for checking that a certain function call triggers a ``DeprecationWarning`` or ``PendingDeprecationWarning``:: import pytest def test_global(): pytest.deprecated_call(myfunction, 17) By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide them. If you wish to record them in your own code, use the command ``warnings.simplefilter('always')``:: import warnings import pytest def test_deprecation(recwarn): warnings.simplefilter('always') warnings.warn("deprecated", DeprecationWarning) assert len(recwarn) == 1 assert recwarn.pop(DeprecationWarning) You can also use it as a contextmanager:: def test_global(): with pytest.deprecated_call(): myobject.deprecated_method()