Remove deprecated nose support
This commit is contained in:
parent
0591569b4b
commit
0f18a7fe5e
|
@ -97,8 +97,8 @@ Features
|
||||||
- `Modular fixtures <https://docs.pytest.org/en/stable/explanation/fixtures.html>`_ for
|
- `Modular fixtures <https://docs.pytest.org/en/stable/explanation/fixtures.html>`_ for
|
||||||
managing small or parametrized long-lived test resources
|
managing small or parametrized long-lived test resources
|
||||||
|
|
||||||
- Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial),
|
- Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial)
|
||||||
`nose <https://docs.pytest.org/en/stable/how-to/nose.html>`_ test suites out of the box
|
test suites out of the box
|
||||||
|
|
||||||
- Python 3.8+ or PyPy3
|
- Python 3.8+ or PyPy3
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ Partner projects, sign up here! (by 22 March)
|
||||||
What does it mean to "adopt pytest"?
|
What does it mean to "adopt pytest"?
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
There can be many different definitions of "success". Pytest can run many nose_ and unittest_ tests by default, so using pytest as your testrunner may be possible from day 1. Job done, right?
|
There can be many different definitions of "success". Pytest can run many unittest_ tests by default, so using pytest as your testrunner may be possible from day 1. Job done, right?
|
||||||
|
|
||||||
Progressive success might look like:
|
Progressive success might look like:
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@ Progressive success might look like:
|
||||||
|
|
||||||
It may be after the month is up, the partner project decides that pytest is not right for it. That's okay - hopefully the pytest team will also learn something about its weaknesses or deficiencies.
|
It may be after the month is up, the partner project decides that pytest is not right for it. That's okay - hopefully the pytest team will also learn something about its weaknesses or deficiencies.
|
||||||
|
|
||||||
.. _nose: nose.html
|
|
||||||
.. _unittest: unittest.html
|
.. _unittest: unittest.html
|
||||||
.. _assert: assert.html
|
.. _assert: assert.html
|
||||||
.. _pycmd: https://bitbucket.org/hpk42/pycmd/overview
|
.. _pycmd: https://bitbucket.org/hpk42/pycmd/overview
|
||||||
|
|
|
@ -44,7 +44,6 @@ How-to guides
|
||||||
|
|
||||||
how-to/existingtestsuite
|
how-to/existingtestsuite
|
||||||
how-to/unittest
|
how-to/unittest
|
||||||
how-to/nose
|
|
||||||
how-to/xunit_setup
|
how-to/xunit_setup
|
||||||
|
|
||||||
how-to/bash-completion
|
how-to/bash-completion
|
||||||
|
|
|
@ -19,113 +19,6 @@ Below is a complete list of all pytest features which are considered deprecated.
|
||||||
:class:`~pytest.PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
|
:class:`~pytest.PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
|
||||||
|
|
||||||
|
|
||||||
.. _nose-deprecation:
|
|
||||||
|
|
||||||
Support for tests written for nose
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. deprecated:: 7.2
|
|
||||||
|
|
||||||
Support for running tests written for `nose <https://nose.readthedocs.io/en/latest/>`__ is now deprecated.
|
|
||||||
|
|
||||||
``nose`` has been in maintenance mode-only for years, and maintaining the plugin is not trivial as it spills
|
|
||||||
over the code base (see :issue:`9886` for more details).
|
|
||||||
|
|
||||||
setup/teardown
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
One thing that might catch users by surprise is that plain ``setup`` and ``teardown`` methods are not pytest native,
|
|
||||||
they are in fact part of the ``nose`` support.
|
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
class Test:
|
|
||||||
def setup(self):
|
|
||||||
self.resource = make_resource()
|
|
||||||
|
|
||||||
def teardown(self):
|
|
||||||
self.resource.close()
|
|
||||||
|
|
||||||
def test_foo(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
def test_bar(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Native pytest support uses ``setup_method`` and ``teardown_method`` (see :ref:`xunit-method-setup`), so the above should be changed to:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
class Test:
|
|
||||||
def setup_method(self):
|
|
||||||
self.resource = make_resource()
|
|
||||||
|
|
||||||
def teardown_method(self):
|
|
||||||
self.resource.close()
|
|
||||||
|
|
||||||
def test_foo(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
def test_bar(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
This is easy to do in an entire code base by doing a simple find/replace.
|
|
||||||
|
|
||||||
@with_setup
|
|
||||||
^^^^^^^^^^^
|
|
||||||
|
|
||||||
Code using `@with_setup <with-setup-nose>`_ such as this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from nose.tools import with_setup
|
|
||||||
|
|
||||||
|
|
||||||
def setup_some_resource():
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
def teardown_some_resource():
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
@with_setup(setup_some_resource, teardown_some_resource)
|
|
||||||
def test_foo():
|
|
||||||
...
|
|
||||||
|
|
||||||
Will also need to be ported to a supported pytest style. One way to do it is using a fixture:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def setup_some_resource():
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
def teardown_some_resource():
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def some_resource():
|
|
||||||
setup_some_resource()
|
|
||||||
yield
|
|
||||||
teardown_some_resource()
|
|
||||||
|
|
||||||
|
|
||||||
def test_foo(some_resource):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
.. _`with-setup-nose`: https://nose.readthedocs.io/en/latest/testing_tools.html?highlight=with_setup#nose.tools.with_setup
|
|
||||||
|
|
||||||
|
|
||||||
.. _node-ctor-fspath-deprecation:
|
.. _node-ctor-fspath-deprecation:
|
||||||
|
|
||||||
``fspath`` argument for Node constructors replaced with ``pathlib.Path``
|
``fspath`` argument for Node constructors replaced with ``pathlib.Path``
|
||||||
|
@ -383,6 +276,115 @@ an appropriate period of deprecation has passed.
|
||||||
|
|
||||||
Some breaking changes which could not be deprecated are also listed.
|
Some breaking changes which could not be deprecated are also listed.
|
||||||
|
|
||||||
|
.. _nose-deprecation:
|
||||||
|
|
||||||
|
Support for tests written for nose
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. deprecated:: 7.2
|
||||||
|
.. versionremoved:: 8.0
|
||||||
|
|
||||||
|
Support for running tests written for `nose <https://nose.readthedocs.io/en/latest/>`__ is now deprecated.
|
||||||
|
|
||||||
|
``nose`` has been in maintenance mode-only for years, and maintaining the plugin is not trivial as it spills
|
||||||
|
over the code base (see :issue:`9886` for more details).
|
||||||
|
|
||||||
|
setup/teardown
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
One thing that might catch users by surprise is that plain ``setup`` and ``teardown`` methods are not pytest native,
|
||||||
|
they are in fact part of the ``nose`` support.
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class Test:
|
||||||
|
def setup(self):
|
||||||
|
self.resource = make_resource()
|
||||||
|
|
||||||
|
def teardown(self):
|
||||||
|
self.resource.close()
|
||||||
|
|
||||||
|
def test_foo(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def test_bar(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Native pytest support uses ``setup_method`` and ``teardown_method`` (see :ref:`xunit-method-setup`), so the above should be changed to:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class Test:
|
||||||
|
def setup_method(self):
|
||||||
|
self.resource = make_resource()
|
||||||
|
|
||||||
|
def teardown_method(self):
|
||||||
|
self.resource.close()
|
||||||
|
|
||||||
|
def test_foo(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def test_bar(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
This is easy to do in an entire code base by doing a simple find/replace.
|
||||||
|
|
||||||
|
@with_setup
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Code using `@with_setup <with-setup-nose>`_ such as this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from nose.tools import with_setup
|
||||||
|
|
||||||
|
|
||||||
|
def setup_some_resource():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_some_resource():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@with_setup(setup_some_resource, teardown_some_resource)
|
||||||
|
def test_foo():
|
||||||
|
...
|
||||||
|
|
||||||
|
Will also need to be ported to a supported pytest style. One way to do it is using a fixture:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
def setup_some_resource():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_some_resource():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def some_resource():
|
||||||
|
setup_some_resource()
|
||||||
|
yield
|
||||||
|
teardown_some_resource()
|
||||||
|
|
||||||
|
|
||||||
|
def test_foo(some_resource):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
.. _`with-setup-nose`: https://nose.readthedocs.io/en/latest/testing_tools.html?highlight=with_setup#nose.tools.with_setup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Passing ``msg=`` to ``pytest.skip``, ``pytest.fail`` or ``pytest.exit``
|
Passing ``msg=`` to ``pytest.skip``, ``pytest.fail`` or ``pytest.exit``
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ For basic examples, see
|
||||||
- :ref:`Fixtures <fixtures>` for basic fixture/setup examples
|
- :ref:`Fixtures <fixtures>` for basic fixture/setup examples
|
||||||
- :ref:`parametrize` for basic test function parametrization
|
- :ref:`parametrize` for basic test function parametrization
|
||||||
- :ref:`unittest` for basic unittest integration
|
- :ref:`unittest` for basic unittest integration
|
||||||
- :ref:`noseintegration` for basic nosetests integration
|
|
||||||
|
|
||||||
The following examples aim at various use cases you might encounter.
|
The following examples aim at various use cases you might encounter.
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ style of setup/teardown functions:
|
||||||
In addition, pytest continues to support :ref:`xunitsetup`. You can mix
|
In addition, pytest continues to support :ref:`xunitsetup`. You can mix
|
||||||
both styles, moving incrementally from classic to new style, as you
|
both styles, moving incrementally from classic to new style, as you
|
||||||
prefer. You can also start out from existing :ref:`unittest.TestCase
|
prefer. You can also start out from existing :ref:`unittest.TestCase
|
||||||
style <unittest.TestCase>` or :ref:`nose based <nosestyle>` projects.
|
style <unittest.TestCase>`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ How to use pytest with an existing test suite
|
||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
Pytest can be used with most existing test suites, but its
|
Pytest can be used with most existing test suites, but its
|
||||||
behavior differs from other test runners such as :ref:`nose <noseintegration>` or
|
behavior differs from other test runners such as Python's
|
||||||
Python's default unittest framework.
|
default unittest framework.
|
||||||
|
|
||||||
Before using this section you will want to :ref:`install pytest <getstarted>`.
|
Before using this section you will want to :ref:`install pytest <getstarted>`.
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ pytest and other test systems
|
||||||
|
|
||||||
existingtestsuite
|
existingtestsuite
|
||||||
unittest
|
unittest
|
||||||
nose
|
|
||||||
xunit_setup
|
xunit_setup
|
||||||
|
|
||||||
pytest development environment
|
pytest development environment
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
.. _`noseintegration`:
|
|
||||||
|
|
||||||
How to run tests written for nose
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
``pytest`` has basic support for running tests written for nose_.
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
This functionality has been deprecated and is likely to be removed in ``pytest 8.x``.
|
|
||||||
|
|
||||||
.. _nosestyle:
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-------------
|
|
||||||
|
|
||||||
After :ref:`installation` type:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python setup.py develop # make sure tests can import our package
|
|
||||||
pytest # instead of 'nosetests'
|
|
||||||
|
|
||||||
and you should be able to run your nose style tests and
|
|
||||||
make use of pytest's capabilities.
|
|
||||||
|
|
||||||
Supported nose Idioms
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
* ``setup()`` and ``teardown()`` at module/class/method level: any function or method called ``setup`` will be called during the setup phase for each test, same for ``teardown``.
|
|
||||||
* ``SkipTest`` exceptions and markers
|
|
||||||
* setup/teardown decorators
|
|
||||||
* ``__test__`` attribute on modules/classes/functions
|
|
||||||
* general usage of nose utilities
|
|
||||||
|
|
||||||
Unsupported idioms / known issues
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
- unittest-style ``setUp, tearDown, setUpClass, tearDownClass``
|
|
||||||
are recognized only on ``unittest.TestCase`` classes but not
|
|
||||||
on plain classes. ``nose`` supports these methods also on plain
|
|
||||||
classes but pytest deliberately does not. As nose and pytest already
|
|
||||||
both support ``setup_class, teardown_class, setup_method, teardown_method``
|
|
||||||
it doesn't seem useful to duplicate the unittest-API like nose does.
|
|
||||||
If you however rather think pytest should support the unittest-spelling on
|
|
||||||
plain classes please post to :issue:`377`.
|
|
||||||
|
|
||||||
- nose imports test modules with the same import path (e.g.
|
|
||||||
``tests.test_mode``) but different file system paths
|
|
||||||
(e.g. ``tests/test_mode.py`` and ``other/tests/test_mode.py``)
|
|
||||||
by extending sys.path/import semantics. pytest does not do that. Note that
|
|
||||||
`nose2 choose to avoid this sys.path/import hackery <https://nose2.readthedocs.io/en/latest/differences.html#test-discovery-and-loading>`_.
|
|
||||||
|
|
||||||
If you place a conftest.py file in the root directory of your project
|
|
||||||
(as determined by pytest) pytest will run tests "nose style" against
|
|
||||||
the code below that directory by adding it to your ``sys.path`` instead of
|
|
||||||
running against your installed code.
|
|
||||||
|
|
||||||
You may find yourself wanting to do this if you ran ``python setup.py install``
|
|
||||||
to set up your project, as opposed to ``python setup.py develop`` or any of
|
|
||||||
the package manager equivalents. Installing with develop in a
|
|
||||||
virtual environment like tox is recommended over this pattern.
|
|
||||||
|
|
||||||
- nose-style doctests are not collected and executed correctly,
|
|
||||||
also doctest fixtures don't work.
|
|
||||||
|
|
||||||
- no nose-configuration is recognized.
|
|
||||||
|
|
||||||
- ``yield``-based methods are
|
|
||||||
fundamentally incompatible with pytest because they don't support fixtures
|
|
||||||
properly since collection and test execution are separated.
|
|
||||||
|
|
||||||
Here is a table comparing the default supported naming conventions for both
|
|
||||||
nose and pytest.
|
|
||||||
|
|
||||||
========= ========================== ======= =====
|
|
||||||
what default naming convention pytest nose
|
|
||||||
========= ========================== ======= =====
|
|
||||||
module ``test*.py`` ✅
|
|
||||||
module ``test_*.py`` ✅ ✅
|
|
||||||
module ``*_test.py`` ✅
|
|
||||||
module ``*_tests.py``
|
|
||||||
class ``*(unittest.TestCase)`` ✅ ✅
|
|
||||||
method ``test_*`` ✅ ✅
|
|
||||||
class ``Test*`` ✅
|
|
||||||
method ``test_*`` ✅
|
|
||||||
function ``test_*`` ✅
|
|
||||||
========= ========================== ======= =====
|
|
||||||
|
|
||||||
|
|
||||||
Migrating from nose to pytest
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
`nose2pytest <https://github.com/pytest-dev/nose2pytest>`_ is a Python script
|
|
||||||
and pytest plugin to help convert Nose-based tests into pytest-based tests.
|
|
||||||
Specifically, the script transforms ``nose.tools.assert_*`` function calls into
|
|
||||||
raw assert statements, while preserving format of original arguments
|
|
||||||
as much as possible.
|
|
||||||
|
|
||||||
.. _nose: https://nose.readthedocs.io/en/latest/
|
|
|
@ -74,7 +74,7 @@ Features
|
||||||
|
|
||||||
- :ref:`Modular fixtures <fixture>` for managing small or parametrized long-lived test resources
|
- :ref:`Modular fixtures <fixture>` for managing small or parametrized long-lived test resources
|
||||||
|
|
||||||
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box
|
- Can run :ref:`unittest <unittest>` (including trial) test suites out of the box
|
||||||
|
|
||||||
- Python 3.8+ or PyPy 3
|
- Python 3.8+ or PyPy 3
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,6 @@ testing =
|
||||||
attrs>=19.2.0
|
attrs>=19.2.0
|
||||||
hypothesis>=3.56
|
hypothesis>=3.56
|
||||||
mock
|
mock
|
||||||
nose
|
|
||||||
pygments>=2.7.2
|
pygments>=2.7.2
|
||||||
requests
|
requests
|
||||||
setuptools
|
setuptools
|
||||||
|
|
|
@ -252,7 +252,6 @@ default_plugins = essential_plugins + (
|
||||||
"monkeypatch",
|
"monkeypatch",
|
||||||
"recwarn",
|
"recwarn",
|
||||||
"pastebin",
|
"pastebin",
|
||||||
"nose",
|
|
||||||
"assertion",
|
"assertion",
|
||||||
"junitxml",
|
"junitxml",
|
||||||
"doctest",
|
"doctest",
|
||||||
|
|
|
@ -23,21 +23,6 @@ DEPRECATED_EXTERNAL_PLUGINS = {
|
||||||
"pytest_faulthandler",
|
"pytest_faulthandler",
|
||||||
}
|
}
|
||||||
|
|
||||||
NOSE_SUPPORT = UnformattedWarning(
|
|
||||||
PytestRemovedIn8Warning,
|
|
||||||
"Support for nose tests is deprecated and will be removed in a future release.\n"
|
|
||||||
"{nodeid} is using nose method: `{method}` ({stage})\n"
|
|
||||||
"See docs: https://docs.pytest.org/en/stable/deprecations.html#support-for-tests-written-for-nose",
|
|
||||||
)
|
|
||||||
|
|
||||||
NOSE_SUPPORT_METHOD = UnformattedWarning(
|
|
||||||
PytestRemovedIn8Warning,
|
|
||||||
"Support for nose tests is deprecated and will be removed in a future release.\n"
|
|
||||||
"{nodeid} is using nose-specific method: `{method}(self)`\n"
|
|
||||||
"To remove this warning, rename it to `{method}_method(self)`\n"
|
|
||||||
"See docs: https://docs.pytest.org/en/stable/deprecations.html#support-for-tests-written-for-nose",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# This can be* removed pytest 8, but it's harmless and common, so no rush to remove.
|
# This can be* removed pytest 8, but it's harmless and common, so no rush to remove.
|
||||||
# * If you're in the future: "could have been".
|
# * If you're in the future: "could have been".
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
"""Run testsuites written for nose."""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
from _pytest.config import hookimpl
|
|
||||||
from _pytest.deprecated import NOSE_SUPPORT
|
|
||||||
from _pytest.fixtures import getfixturemarker
|
|
||||||
from _pytest.nodes import Item
|
|
||||||
from _pytest.python import Function
|
|
||||||
from _pytest.unittest import TestCaseFunction
|
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(trylast=True)
|
|
||||||
def pytest_runtest_setup(item: Item) -> None:
|
|
||||||
if not isinstance(item, Function):
|
|
||||||
return
|
|
||||||
# Don't do nose style setup/teardown on direct unittest style classes.
|
|
||||||
if isinstance(item, TestCaseFunction):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Capture the narrowed type of item for the teardown closure,
|
|
||||||
# see https://github.com/python/mypy/issues/2608
|
|
||||||
func = item
|
|
||||||
|
|
||||||
call_optional(func.obj, "setup", func.nodeid)
|
|
||||||
func.addfinalizer(lambda: call_optional(func.obj, "teardown", func.nodeid))
|
|
||||||
|
|
||||||
# NOTE: Module- and class-level fixtures are handled in python.py
|
|
||||||
# with `pluginmanager.has_plugin("nose")` checks.
|
|
||||||
# It would have been nicer to implement them outside of core, but
|
|
||||||
# it's not straightforward.
|
|
||||||
|
|
||||||
|
|
||||||
def call_optional(obj: object, name: str, nodeid: str) -> bool:
|
|
||||||
method = getattr(obj, name, None)
|
|
||||||
if method is None:
|
|
||||||
return False
|
|
||||||
is_fixture = getfixturemarker(method) is not None
|
|
||||||
if is_fixture:
|
|
||||||
return False
|
|
||||||
if not callable(method):
|
|
||||||
return False
|
|
||||||
# Warn about deprecation of this plugin.
|
|
||||||
method_name = getattr(method, "__name__", str(method))
|
|
||||||
warnings.warn(
|
|
||||||
NOSE_SUPPORT.format(nodeid=nodeid, method=method_name, stage=name), stacklevel=2
|
|
||||||
)
|
|
||||||
# If there are any problems allow the exception to raise rather than
|
|
||||||
# silently ignoring it.
|
|
||||||
method()
|
|
||||||
return True
|
|
|
@ -57,7 +57,6 @@ from _pytest.config import ExitCode
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
from _pytest.deprecated import check_ispytest
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.deprecated import NOSE_SUPPORT_METHOD
|
|
||||||
from _pytest.fixtures import FixtureDef
|
from _pytest.fixtures import FixtureDef
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.fixtures import FuncFixtureInfo
|
from _pytest.fixtures import FuncFixtureInfo
|
||||||
|
@ -596,23 +595,12 @@ class Module(nodes.File, PyCollector):
|
||||||
Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
|
Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
|
||||||
other fixtures (#517).
|
other fixtures (#517).
|
||||||
"""
|
"""
|
||||||
has_nose = self.config.pluginmanager.has_plugin("nose")
|
|
||||||
setup_module = _get_first_non_fixture_func(
|
setup_module = _get_first_non_fixture_func(
|
||||||
self.obj, ("setUpModule", "setup_module")
|
self.obj, ("setUpModule", "setup_module")
|
||||||
)
|
)
|
||||||
if setup_module is None and has_nose:
|
|
||||||
# The name "setup" is too common - only treat as fixture if callable.
|
|
||||||
setup_module = _get_first_non_fixture_func(self.obj, ("setup",))
|
|
||||||
if not callable(setup_module):
|
|
||||||
setup_module = None
|
|
||||||
teardown_module = _get_first_non_fixture_func(
|
teardown_module = _get_first_non_fixture_func(
|
||||||
self.obj, ("tearDownModule", "teardown_module")
|
self.obj, ("tearDownModule", "teardown_module")
|
||||||
)
|
)
|
||||||
if teardown_module is None and has_nose:
|
|
||||||
teardown_module = _get_first_non_fixture_func(self.obj, ("teardown",))
|
|
||||||
# Same as "setup" above - only treat as fixture if callable.
|
|
||||||
if not callable(teardown_module):
|
|
||||||
teardown_module = None
|
|
||||||
|
|
||||||
if setup_module is None and teardown_module is None:
|
if setup_module is None and teardown_module is None:
|
||||||
return
|
return
|
||||||
|
@ -853,21 +841,10 @@ class Class(PyCollector):
|
||||||
Using a fixture to invoke these methods ensures we play nicely and unsurprisingly with
|
Using a fixture to invoke these methods ensures we play nicely and unsurprisingly with
|
||||||
other fixtures (#517).
|
other fixtures (#517).
|
||||||
"""
|
"""
|
||||||
has_nose = self.config.pluginmanager.has_plugin("nose")
|
|
||||||
setup_name = "setup_method"
|
setup_name = "setup_method"
|
||||||
setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
|
setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
|
||||||
emit_nose_setup_warning = False
|
|
||||||
if setup_method is None and has_nose:
|
|
||||||
setup_name = "setup"
|
|
||||||
emit_nose_setup_warning = True
|
|
||||||
setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
|
|
||||||
teardown_name = "teardown_method"
|
teardown_name = "teardown_method"
|
||||||
teardown_method = _get_first_non_fixture_func(self.obj, (teardown_name,))
|
teardown_method = _get_first_non_fixture_func(self.obj, (teardown_name,))
|
||||||
emit_nose_teardown_warning = False
|
|
||||||
if teardown_method is None and has_nose:
|
|
||||||
teardown_name = "teardown"
|
|
||||||
emit_nose_teardown_warning = True
|
|
||||||
teardown_method = _get_first_non_fixture_func(self.obj, (teardown_name,))
|
|
||||||
if setup_method is None and teardown_method is None:
|
if setup_method is None and teardown_method is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -882,24 +859,10 @@ class Class(PyCollector):
|
||||||
if setup_method is not None:
|
if setup_method is not None:
|
||||||
func = getattr(self, setup_name)
|
func = getattr(self, setup_name)
|
||||||
_call_with_optional_argument(func, method)
|
_call_with_optional_argument(func, method)
|
||||||
if emit_nose_setup_warning:
|
|
||||||
warnings.warn(
|
|
||||||
NOSE_SUPPORT_METHOD.format(
|
|
||||||
nodeid=request.node.nodeid, method="setup"
|
|
||||||
),
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
yield
|
yield
|
||||||
if teardown_method is not None:
|
if teardown_method is not None:
|
||||||
func = getattr(self, teardown_name)
|
func = getattr(self, teardown_name)
|
||||||
_call_with_optional_argument(func, method)
|
_call_with_optional_argument(func, method)
|
||||||
if emit_nose_teardown_warning:
|
|
||||||
warnings.warn(
|
|
||||||
NOSE_SUPPORT_METHOD.format(
|
|
||||||
nodeid=request.node.nodeid, method="teardown"
|
|
||||||
),
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.obj.__pytest_setup_method = xunit_setup_method_fixture
|
self.obj.__pytest_setup_method = xunit_setup_method_fixture
|
||||||
|
|
||||||
|
|
|
@ -188,62 +188,3 @@ def test_fixture_disallowed_between_marks():
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
assert len(record) == 2 # one for each mark decorator
|
assert len(record) == 2 # one for each mark decorator
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.filterwarnings("default")
|
|
||||||
def test_nose_deprecated_with_setup(pytester: Pytester) -> None:
|
|
||||||
pytest.importorskip("nose")
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
from nose.tools import with_setup
|
|
||||||
|
|
||||||
def setup_fn_no_op():
|
|
||||||
...
|
|
||||||
|
|
||||||
def teardown_fn_no_op():
|
|
||||||
...
|
|
||||||
|
|
||||||
@with_setup(setup_fn_no_op, teardown_fn_no_op)
|
|
||||||
def test_omits_warnings():
|
|
||||||
...
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
output = pytester.runpytest("-Wdefault::pytest.PytestRemovedIn8Warning")
|
|
||||||
message = [
|
|
||||||
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
|
|
||||||
"*test_nose_deprecated_with_setup.py::test_omits_warnings is using nose method: `setup_fn_no_op` (setup)",
|
|
||||||
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
|
|
||||||
"*test_nose_deprecated_with_setup.py::test_omits_warnings is using nose method: `teardown_fn_no_op` (teardown)",
|
|
||||||
]
|
|
||||||
output.stdout.fnmatch_lines(message)
|
|
||||||
output.assert_outcomes(passed=1)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.filterwarnings("default")
|
|
||||||
def test_nose_deprecated_setup_teardown(pytester: Pytester) -> None:
|
|
||||||
pytest.importorskip("nose")
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
class Test:
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
def teardown(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
def test(self):
|
|
||||||
...
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
output = pytester.runpytest("-Wdefault::pytest.PytestRemovedIn8Warning")
|
|
||||||
message = [
|
|
||||||
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
|
|
||||||
"*test_nose_deprecated_setup_teardown.py::Test::test is using nose-specific method: `setup(self)`",
|
|
||||||
"*To remove this warning, rename it to `setup_method(self)`",
|
|
||||||
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
|
|
||||||
"*test_nose_deprecated_setup_teardown.py::Test::test is using nose-specific method: `teardown(self)`",
|
|
||||||
"*To remove this warning, rename it to `teardown_method(self)`",
|
|
||||||
]
|
|
||||||
output.stdout.fnmatch_lines(message)
|
|
||||||
output.assert_outcomes(passed=1)
|
|
||||||
|
|
|
@ -1,529 +0,0 @@
|
||||||
import pytest
|
|
||||||
from _pytest.pytester import Pytester
|
|
||||||
|
|
||||||
|
|
||||||
def setup_module(mod):
|
|
||||||
mod.nose = pytest.importorskip("nose")
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_setup(pytester: Pytester) -> None:
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
values = []
|
|
||||||
from nose.tools import with_setup
|
|
||||||
|
|
||||||
@with_setup(lambda: values.append(1), lambda: values.append(2))
|
|
||||||
def test_hello():
|
|
||||||
assert values == [1]
|
|
||||||
|
|
||||||
def test_world():
|
|
||||||
assert values == [1,2]
|
|
||||||
|
|
||||||
test_hello.setup = lambda: values.append(1)
|
|
||||||
test_hello.teardown = lambda: values.append(2)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(
|
|
||||||
p, "-p", "nose", "-Wignore::pytest.PytestRemovedIn8Warning"
|
|
||||||
)
|
|
||||||
result.assert_outcomes(passed=2)
|
|
||||||
|
|
||||||
|
|
||||||
def test_setup_func_with_setup_decorator() -> None:
|
|
||||||
from _pytest.nose import call_optional
|
|
||||||
|
|
||||||
values = []
|
|
||||||
|
|
||||||
class A:
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def f(self):
|
|
||||||
values.append(1)
|
|
||||||
|
|
||||||
call_optional(A(), "f", "A.f")
|
|
||||||
assert not values
|
|
||||||
|
|
||||||
|
|
||||||
def test_setup_func_not_callable() -> None:
|
|
||||||
from _pytest.nose import call_optional
|
|
||||||
|
|
||||||
class A:
|
|
||||||
f = 1
|
|
||||||
|
|
||||||
call_optional(A(), "f", "A.f")
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_setup_func(pytester: Pytester) -> None:
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
from nose.tools import with_setup
|
|
||||||
|
|
||||||
values = []
|
|
||||||
|
|
||||||
def my_setup():
|
|
||||||
a = 1
|
|
||||||
values.append(a)
|
|
||||||
|
|
||||||
def my_teardown():
|
|
||||||
b = 2
|
|
||||||
values.append(b)
|
|
||||||
|
|
||||||
@with_setup(my_setup, my_teardown)
|
|
||||||
def test_hello():
|
|
||||||
print(values)
|
|
||||||
assert values == [1]
|
|
||||||
|
|
||||||
def test_world():
|
|
||||||
print(values)
|
|
||||||
assert values == [1,2]
|
|
||||||
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(
|
|
||||||
p, "-p", "nose", "-Wignore::pytest.PytestRemovedIn8Warning"
|
|
||||||
)
|
|
||||||
result.assert_outcomes(passed=2)
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_setup_func_failure(pytester: Pytester) -> None:
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
from nose.tools import with_setup
|
|
||||||
|
|
||||||
values = []
|
|
||||||
my_setup = lambda x: 1
|
|
||||||
my_teardown = lambda x: 2
|
|
||||||
|
|
||||||
@with_setup(my_setup, my_teardown)
|
|
||||||
def test_hello():
|
|
||||||
print(values)
|
|
||||||
assert values == [1]
|
|
||||||
|
|
||||||
def test_world():
|
|
||||||
print(values)
|
|
||||||
assert values == [1,2]
|
|
||||||
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(
|
|
||||||
p, "-p", "nose", "-Wignore::pytest.PytestRemovedIn8Warning"
|
|
||||||
)
|
|
||||||
result.stdout.fnmatch_lines(["*TypeError: <lambda>()*"])
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_setup_func_failure_2(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
values = []
|
|
||||||
|
|
||||||
my_setup = 1
|
|
||||||
my_teardown = 2
|
|
||||||
|
|
||||||
def test_hello():
|
|
||||||
assert values == []
|
|
||||||
|
|
||||||
test_hello.setup = my_setup
|
|
||||||
test_hello.teardown = my_teardown
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
reprec = pytester.inline_run()
|
|
||||||
reprec.assertoutcome(passed=1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_setup_partial(pytester: Pytester) -> None:
|
|
||||||
pytest.importorskip("functools")
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
values = []
|
|
||||||
|
|
||||||
def my_setup(x):
|
|
||||||
a = x
|
|
||||||
values.append(a)
|
|
||||||
|
|
||||||
def my_teardown(x):
|
|
||||||
b = x
|
|
||||||
values.append(b)
|
|
||||||
|
|
||||||
my_setup_partial = partial(my_setup, 1)
|
|
||||||
my_teardown_partial = partial(my_teardown, 2)
|
|
||||||
|
|
||||||
def test_hello():
|
|
||||||
print(values)
|
|
||||||
assert values == [1]
|
|
||||||
|
|
||||||
def test_world():
|
|
||||||
print(values)
|
|
||||||
assert values == [1,2]
|
|
||||||
|
|
||||||
test_hello.setup = my_setup_partial
|
|
||||||
test_hello.teardown = my_teardown_partial
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(
|
|
||||||
p, "-p", "nose", "-Wignore::pytest.PytestRemovedIn8Warning"
|
|
||||||
)
|
|
||||||
result.stdout.fnmatch_lines(["*2 passed*"])
|
|
||||||
|
|
||||||
|
|
||||||
def test_module_level_setup(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
from nose.tools import with_setup
|
|
||||||
items = {}
|
|
||||||
|
|
||||||
def setup():
|
|
||||||
items.setdefault("setup", []).append("up")
|
|
||||||
|
|
||||||
def teardown():
|
|
||||||
items.setdefault("setup", []).append("down")
|
|
||||||
|
|
||||||
def setup2():
|
|
||||||
items.setdefault("setup2", []).append("up")
|
|
||||||
|
|
||||||
def teardown2():
|
|
||||||
items.setdefault("setup2", []).append("down")
|
|
||||||
|
|
||||||
def test_setup_module_setup():
|
|
||||||
assert items["setup"] == ["up"]
|
|
||||||
|
|
||||||
def test_setup_module_setup_again():
|
|
||||||
assert items["setup"] == ["up"]
|
|
||||||
|
|
||||||
@with_setup(setup2, teardown2)
|
|
||||||
def test_local_setup():
|
|
||||||
assert items["setup"] == ["up"]
|
|
||||||
assert items["setup2"] == ["up"]
|
|
||||||
|
|
||||||
@with_setup(setup2, teardown2)
|
|
||||||
def test_local_setup_again():
|
|
||||||
assert items["setup"] == ["up"]
|
|
||||||
assert items["setup2"] == ["up", "down", "up"]
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(
|
|
||||||
"-p", "nose", "-Wignore::pytest.PytestRemovedIn8Warning"
|
|
||||||
)
|
|
||||||
result.stdout.fnmatch_lines(["*4 passed*"])
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_style_setup_teardown(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
values = []
|
|
||||||
|
|
||||||
def setup_module():
|
|
||||||
values.append(1)
|
|
||||||
|
|
||||||
def teardown_module():
|
|
||||||
del values[0]
|
|
||||||
|
|
||||||
def test_hello():
|
|
||||||
assert values == [1]
|
|
||||||
|
|
||||||
def test_world():
|
|
||||||
assert values == [1]
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest("-p", "nose")
|
|
||||||
result.stdout.fnmatch_lines(["*2 passed*"])
|
|
||||||
|
|
||||||
|
|
||||||
def test_fixtures_nose_setup_issue8394(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
def setup_module():
|
|
||||||
pass
|
|
||||||
|
|
||||||
def teardown_module():
|
|
||||||
pass
|
|
||||||
|
|
||||||
def setup_function(func):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def teardown_function(func):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_world():
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Test(object):
|
|
||||||
def setup_class(cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def teardown_class(cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def setup_method(self, meth):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def teardown_method(self, meth):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_method(self): pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
match = "*no docstring available*"
|
|
||||||
result = pytester.runpytest("--fixtures")
|
|
||||||
assert result.ret == 0
|
|
||||||
result.stdout.no_fnmatch_line(match)
|
|
||||||
|
|
||||||
result = pytester.runpytest("--fixtures", "-v")
|
|
||||||
assert result.ret == 0
|
|
||||||
result.stdout.fnmatch_lines([match, match, match, match])
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_setup_ordering(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
def setup_module(mod):
|
|
||||||
mod.visited = True
|
|
||||||
|
|
||||||
class TestClass(object):
|
|
||||||
def setup(self):
|
|
||||||
assert visited
|
|
||||||
self.visited_cls = True
|
|
||||||
def test_first(self):
|
|
||||||
assert visited
|
|
||||||
assert self.visited_cls
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest("-Wignore::pytest.PytestRemovedIn8Warning")
|
|
||||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
|
||||||
|
|
||||||
|
|
||||||
def test_apiwrapper_problem_issue260(pytester: Pytester) -> None:
|
|
||||||
# this would end up trying a call an optional teardown on the class
|
|
||||||
# for plain unittests we don't want nose behaviour
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
import unittest
|
|
||||||
class TestCase(unittest.TestCase):
|
|
||||||
def setup(self):
|
|
||||||
#should not be called in unittest testcases
|
|
||||||
assert 0, 'setup'
|
|
||||||
def teardown(self):
|
|
||||||
#should not be called in unittest testcases
|
|
||||||
assert 0, 'teardown'
|
|
||||||
def setUp(self):
|
|
||||||
print('setup')
|
|
||||||
def tearDown(self):
|
|
||||||
print('teardown')
|
|
||||||
def test_fun(self):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest()
|
|
||||||
result.assert_outcomes(passed=1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_setup_teardown_linking_issue265(pytester: Pytester) -> None:
|
|
||||||
# we accidentally didn't integrate nose setupstate with normal setupstate
|
|
||||||
# this test ensures that won't happen again
|
|
||||||
pytester.makepyfile(
|
|
||||||
'''
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
class TestGeneric(object):
|
|
||||||
def test_nothing(self):
|
|
||||||
"""Tests the API of the implementation (for generic and specialized)."""
|
|
||||||
|
|
||||||
@pytest.mark.skipif("True", reason=
|
|
||||||
"Skip tests to check if teardown is skipped as well.")
|
|
||||||
class TestSkipTeardown(TestGeneric):
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
"""Sets up my specialized implementation for $COOL_PLATFORM."""
|
|
||||||
raise Exception("should not call setup for skipped tests")
|
|
||||||
|
|
||||||
def teardown(self):
|
|
||||||
"""Undoes the setup."""
|
|
||||||
raise Exception("should not call teardown for skipped tests")
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
reprec = pytester.runpytest()
|
|
||||||
reprec.assert_outcomes(passed=1, skipped=1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_SkipTest_during_collection(pytester: Pytester) -> None:
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
import nose
|
|
||||||
raise nose.SkipTest("during collection")
|
|
||||||
def test_failing():
|
|
||||||
assert False
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(p)
|
|
||||||
result.assert_outcomes(skipped=1, warnings=0)
|
|
||||||
|
|
||||||
|
|
||||||
def test_SkipTest_in_test(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
import nose
|
|
||||||
|
|
||||||
def test_skipping():
|
|
||||||
raise nose.SkipTest("in test")
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
reprec = pytester.inline_run()
|
|
||||||
reprec.assertoutcome(skipped=1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_istest_function_decorator(pytester: Pytester) -> None:
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
import nose.tools
|
|
||||||
@nose.tools.istest
|
|
||||||
def not_test_prefix():
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(p)
|
|
||||||
result.assert_outcomes(passed=1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_nottest_function_decorator(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
import nose.tools
|
|
||||||
@nose.tools.nottest
|
|
||||||
def test_prefix():
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
reprec = pytester.inline_run()
|
|
||||||
assert not reprec.getfailedcollections()
|
|
||||||
calls = reprec.getreports("pytest_runtest_logreport")
|
|
||||||
assert not calls
|
|
||||||
|
|
||||||
|
|
||||||
def test_istest_class_decorator(pytester: Pytester) -> None:
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
import nose.tools
|
|
||||||
@nose.tools.istest
|
|
||||||
class NotTestPrefix(object):
|
|
||||||
def test_method(self):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(p)
|
|
||||||
result.assert_outcomes(passed=1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_nottest_class_decorator(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
import nose.tools
|
|
||||||
@nose.tools.nottest
|
|
||||||
class TestPrefix(object):
|
|
||||||
def test_method(self):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
reprec = pytester.inline_run()
|
|
||||||
assert not reprec.getfailedcollections()
|
|
||||||
calls = reprec.getreports("pytest_runtest_logreport")
|
|
||||||
assert not calls
|
|
||||||
|
|
||||||
|
|
||||||
def test_skip_test_with_unicode(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""\
|
|
||||||
import unittest
|
|
||||||
class TestClass():
|
|
||||||
def test_io(self):
|
|
||||||
raise unittest.SkipTest('😊')
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest()
|
|
||||||
result.stdout.fnmatch_lines(["* 1 skipped *"])
|
|
||||||
|
|
||||||
|
|
||||||
def test_raises(pytester: Pytester) -> None:
|
|
||||||
pytester.makepyfile(
|
|
||||||
"""
|
|
||||||
from nose.tools import raises
|
|
||||||
|
|
||||||
@raises(RuntimeError)
|
|
||||||
def test_raises_runtimeerror():
|
|
||||||
raise RuntimeError
|
|
||||||
|
|
||||||
@raises(Exception)
|
|
||||||
def test_raises_baseexception_not_caught():
|
|
||||||
raise BaseException
|
|
||||||
|
|
||||||
@raises(BaseException)
|
|
||||||
def test_raises_baseexception_caught():
|
|
||||||
raise BaseException
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest("-vv")
|
|
||||||
result.stdout.fnmatch_lines(
|
|
||||||
[
|
|
||||||
"test_raises.py::test_raises_runtimeerror PASSED*",
|
|
||||||
"test_raises.py::test_raises_baseexception_not_caught FAILED*",
|
|
||||||
"test_raises.py::test_raises_baseexception_caught PASSED*",
|
|
||||||
"*= FAILURES =*",
|
|
||||||
"*_ test_raises_baseexception_not_caught _*",
|
|
||||||
"",
|
|
||||||
"arg = (), kw = {}",
|
|
||||||
"",
|
|
||||||
" def newfunc(*arg, **kw):",
|
|
||||||
" try:",
|
|
||||||
"> func(*arg, **kw)",
|
|
||||||
"",
|
|
||||||
"*/nose/*: ",
|
|
||||||
"_ _ *",
|
|
||||||
"",
|
|
||||||
" @raises(Exception)",
|
|
||||||
" def test_raises_baseexception_not_caught():",
|
|
||||||
"> raise BaseException",
|
|
||||||
"E BaseException",
|
|
||||||
"",
|
|
||||||
"test_raises.py:9: BaseException",
|
|
||||||
"* 1 failed, 2 passed *",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_nose_setup_skipped_if_non_callable(pytester: Pytester) -> None:
|
|
||||||
"""Regression test for #9391."""
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
__init__="",
|
|
||||||
setup="""
|
|
||||||
""",
|
|
||||||
teardown="""
|
|
||||||
""",
|
|
||||||
test_it="""
|
|
||||||
from . import setup, teardown
|
|
||||||
|
|
||||||
def test_it():
|
|
||||||
pass
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(p.parent, "-p", "nose")
|
|
||||||
assert result.ret == 0
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("fixture_name", ("teardown", "teardown_class"))
|
|
||||||
def test_teardown_fixture_not_called_directly(fixture_name, pytester: Pytester) -> None:
|
|
||||||
"""Regression test for #10597."""
|
|
||||||
p = pytester.makepyfile(
|
|
||||||
f"""
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
class TestHello:
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def {fixture_name}(self):
|
|
||||||
yield
|
|
||||||
|
|
||||||
def test_hello(self, {fixture_name}):
|
|
||||||
assert True
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = pytester.runpytest(p, "-p", "nose")
|
|
||||||
assert result.ret == 0
|
|
Loading…
Reference in New Issue