parent
31f9e5bcdd
commit
c988e49af6
1
AUTHORS
1
AUTHORS
|
@ -63,6 +63,7 @@ Ceridwen
|
|||
Charles Cloud
|
||||
Charles Machalow
|
||||
Charnjit SiNGH (CCSJ)
|
||||
Cheuk Ting Ho
|
||||
Chris Lamb
|
||||
Chris NeJame
|
||||
Chris Rose
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
A warning is now emitted if a test function returns something other than `None`. This prevents a common mistake among beginners that expect that returning a `bool` (for example `return foo(a, b) == result`) would cause a test to pass or fail, instead of using `assert`.
|
|
@ -252,6 +252,47 @@ or ``pytest.warns(Warning)``.
|
|||
|
||||
See :ref:`warns use cases` for examples.
|
||||
|
||||
|
||||
Returning non-None value in test functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.2
|
||||
|
||||
A :class:`pytest.PytestReturnNotNoneWarning` is now emitted if a test function returns something other than `None`.
|
||||
|
||||
This prevents a common mistake among beginners that expect that returning a `bool` would cause a test to pass or fail, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["a", "b", "result"],
|
||||
[
|
||||
[1, 2, 5],
|
||||
[2, 3, 8],
|
||||
[5, 3, 18],
|
||||
],
|
||||
)
|
||||
def test_foo(a, b, result):
|
||||
return foo(a, b) == result
|
||||
|
||||
Given that pytest ignores the return value, this might be surprising that it will never fail.
|
||||
|
||||
The proper fix is to change the `return` to an `assert`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["a", "b", "result"],
|
||||
[
|
||||
[1, 2, 5],
|
||||
[2, 3, 8],
|
||||
[5, 3, 18],
|
||||
],
|
||||
)
|
||||
def test_foo(a, b, result):
|
||||
assert foo(a, b) == result
|
||||
|
||||
|
||||
The ``--strict`` command-line option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -1130,6 +1130,9 @@ Custom warnings generated in some situations such as improper usage or deprecate
|
|||
.. autoclass:: pytest.PytestExperimentalApiWarning
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: pytest.PytestReturnNotNoneWarning
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: pytest.PytestUnhandledCoroutineWarning
|
||||
:show-inheritance:
|
||||
|
||||
|
|
|
@ -77,10 +77,12 @@ from _pytest.pathlib import parts
|
|||
from _pytest.pathlib import visit
|
||||
from _pytest.scope import Scope
|
||||
from _pytest.warning_types import PytestCollectionWarning
|
||||
from _pytest.warning_types import PytestReturnNotNoneWarning
|
||||
from _pytest.warning_types import PytestUnhandledCoroutineWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Literal
|
||||
|
||||
from _pytest.scope import _ScopeName
|
||||
|
||||
|
||||
|
@ -192,6 +194,13 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]:
|
|||
result = testfunction(**testargs)
|
||||
if hasattr(result, "__await__") or hasattr(result, "__aiter__"):
|
||||
async_warn_and_skip(pyfuncitem.nodeid)
|
||||
elif result is not None:
|
||||
warnings.warn(
|
||||
PytestReturnNotNoneWarning(
|
||||
f"Expected None, but {pyfuncitem.nodeid} returned {result!r}, which will be an error in a "
|
||||
"future version of pytest. Did you mean to use `assert` instead of `return`?"
|
||||
)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -55,6 +55,13 @@ class PytestRemovedIn8Warning(PytestDeprecationWarning):
|
|||
__module__ = "pytest"
|
||||
|
||||
|
||||
@final
|
||||
class PytestReturnNotNoneWarning(PytestDeprecationWarning):
|
||||
"""Warning emitted when a test function is returning value other than None."""
|
||||
|
||||
__module__ = "pytest"
|
||||
|
||||
|
||||
@final
|
||||
class PytestExperimentalApiWarning(PytestWarning, FutureWarning):
|
||||
"""Warning category used to denote experiments in pytest.
|
||||
|
|
|
@ -69,6 +69,7 @@ from _pytest.warning_types import PytestConfigWarning
|
|||
from _pytest.warning_types import PytestDeprecationWarning
|
||||
from _pytest.warning_types import PytestExperimentalApiWarning
|
||||
from _pytest.warning_types import PytestRemovedIn8Warning
|
||||
from _pytest.warning_types import PytestReturnNotNoneWarning
|
||||
from _pytest.warning_types import PytestUnhandledCoroutineWarning
|
||||
from _pytest.warning_types import PytestUnhandledThreadExceptionWarning
|
||||
from _pytest.warning_types import PytestUnknownMarkWarning
|
||||
|
@ -127,6 +128,7 @@ __all__ = [
|
|||
"PytestDeprecationWarning",
|
||||
"PytestExperimentalApiWarning",
|
||||
"PytestRemovedIn8Warning",
|
||||
"PytestReturnNotNoneWarning",
|
||||
"Pytester",
|
||||
"PytestPluginManager",
|
||||
"PytestUnhandledCoroutineWarning",
|
||||
|
|
|
@ -1292,3 +1292,14 @@ def test_no_brokenpipeerror_message(pytester: Pytester) -> None:
|
|||
|
||||
# Cleanup.
|
||||
popen.stderr.close()
|
||||
|
||||
|
||||
def test_function_return_non_none_warning(testdir) -> None:
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_stuff():
|
||||
return "something"
|
||||
"""
|
||||
)
|
||||
res = testdir.runpytest()
|
||||
res.stdout.fnmatch_lines(["*Did you mean to use `assert` instead of `return`?*"])
|
||||
|
|
Loading…
Reference in New Issue