Skip to content

Dependencies between xunit-style setups and the other fixtures #5949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
stanislavlevin opened this issue Oct 12, 2019 · 5 comments
Open

Dependencies between xunit-style setups and the other fixtures #5949

stanislavlevin opened this issue Oct 12, 2019 · 5 comments
Labels
topic: fixtures anything involving fixtures directly or indirectly

Comments

@stanislavlevin
Copy link

#4091 introduced a nice feature employed xunit-style setups and unittest definitions as internal fixtures.

But unfortunately, it looks like there is no way to make a strict order of fixture setup as It made in case of regular ones. Yes, sure, setup*/teardown* have
their own fixture names, but they are internal, for example:

_Class__pytest_setup_class
_UnitTestCase__pytest_class_setup

I couldn't rely on them since they are not documented and could be different from release to release.

The second problem that even if I drop xunit/unittest setups I can't forbid their usage by Pytest means.

@RonnyPfannschmidt
Copy link
Member

you could make a pytest plugin that raises errors when xunit style setup is used

@stanislavlevin
Copy link
Author

I thought about this.
At first look, I don't see how I can catch this. But since you talk about such a possibility, now I believe there is a good chance to do it.
@RonnyPfannschmidt , could you give me a little hint about a reliable way to catch xunit/unittest?

@stanislavlevin
Copy link
Author

Example of implementation of a such plugin (based on attributes of item.cls):
forbidden.py.txt

Produces output:

module: test_f.py
        setup_module
        setup_function
        class: TestClass
                setup_class
                setup_method

!!!!!!!!!!! _pytest.outcomes.Exit: xunit style setups and unittest are not allowed !!!!!!!!!!!!
==================================== no tests ran in 0.11s ===================================

@RonnyPfannschmidt
Copy link
Member

@stanislavlevin that looks like a good start, if you use the results of the makeitem hooks and use item.warn, you can have to the point warnings for the classes/modules that use xunit style setups

to be on the safe side, please take into account that setup_foo fixtures are allowed anf replace xunit with fixture style

@stanislavlevin
Copy link
Author

stanislavlevin commented Oct 14, 2019

@RonnyPfannschmidt, thank you very much for the clues.
Unfortunately, pytest_pycollect_makeitem doesn't work as I expect or my expectations are wrong.

For example,
test class:

import unittest

class TestClass:
    def test_1(self):
        pass

class TestCase(unittest.TestCase):
    def test_method1(self):
        pass
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makeitem(collector, name, obj):
    outcome = yield
    res = outcome.get_result()
    if res is not None:
        if isinstance(res, list):
            for n in res:
                print(n.name)
        else:
            print(type(res))

Run only one test class test_unittest.py::TestClass.
Outcome:

collecting ... <class '_pytest.python.Class'>
<class '_pytest.unittest.UnitTestCase'>
test_1
collected 1 item

I thought that the result produced by this hook will be filtered by collection (I mean only test_1 in the outcome).

Updated version of plugin:

import sys
import pytest

forb_mod_scope = [
    'setup_module',
    'setup_function',
    'teardown_module',
    'teardown_function',
]

forb_cls_scope = [
    'setup_class',
    'setup_method',
    'teardown_class',
    'teardown_method',
]

def pytest_collection_finish(session):
    unit_test = sys.modules.get('unittest', None)
    unit_test_cls = getattr(unit_test, "TestCase", None)

    for item in session.items:
        cls = getattr(item, 'cls', None)
        subclassed = False
        if unit_test_cls is not None and cls is not None:
             subclassed = issubclass(cls, unit_test_cls)
        if subclassed:
            item.warn(pytest.PytestWarning("unittest is deprecated"))
            continue

        def xunit_depr_warn(item, attr, names):
            for n in names:
                obj = getattr(item, attr, None)
                method = getattr(obj, n, None)
                fixtured = hasattr(method, '__pytest_wrapped__')
                if method is not None and not fixtured:
                    item.warn(pytest.PytestWarning("xunit style is deprecated\n"))
 
        xunit_depr_warn(item, 'module', forb_mod_scope)
        xunit_depr_warn(item, 'cls', forb_cls_scope)

@Zac-HD Zac-HD added the topic: fixtures anything involving fixtures directly or indirectly label Oct 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: fixtures anything involving fixtures directly or indirectly
Projects
None yet
Development

No branches or pull requests

3 participants