Merge pull request #4091 from nicoddemus/setup-methods-as-fixtures-3094
Use fixtures to invoke xunit-style fixtures
This commit is contained in:
		
						commit
						daf39112e7
					
				| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
`Class xunit-style <https://docs.pytest.org/en/latest/xunit_setup.html>`__ functions and methods
 | 
			
		||||
now obey the scope of *autouse* fixtures.
 | 
			
		||||
 | 
			
		||||
This fixes a number of surprising issues like ``setup_method`` being called before session-scoped
 | 
			
		||||
autouse fixtures (see `#517 <https://github.com/pytest-dev/pytest/issues/517>`__ for an example).
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +93,15 @@ Remarks:
 | 
			
		|||
 | 
			
		||||
* It is possible for setup/teardown pairs to be invoked multiple times
 | 
			
		||||
  per testing process.
 | 
			
		||||
 | 
			
		||||
* teardown functions are not called if the corresponding setup function existed
 | 
			
		||||
  and failed/was skipped.
 | 
			
		||||
 | 
			
		||||
* Prior to pytest-4.2, xunit-style functions did not obey the scope rules of fixtures, so
 | 
			
		||||
  it was possible, for example, for a ``setup_method`` to be called before a
 | 
			
		||||
  session-scoped autouse fixture.
 | 
			
		||||
 | 
			
		||||
  Now the xunit-style functions are integrated with the fixture mechanism and obey the proper
 | 
			
		||||
  scope rules of fixtures involved in the call.
 | 
			
		||||
 | 
			
		||||
.. _`unittest.py module`: http://docs.python.org/library/unittest.html
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import inspect
 | 
			
		|||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import warnings
 | 
			
		||||
from functools import partial
 | 
			
		||||
from textwrap import dedent
 | 
			
		||||
 | 
			
		||||
import py
 | 
			
		||||
| 
						 | 
				
			
			@ -432,9 +433,66 @@ class Module(nodes.File, PyCollector):
 | 
			
		|||
        return self._importtestmodule()
 | 
			
		||||
 | 
			
		||||
    def collect(self):
 | 
			
		||||
        self._inject_setup_module_fixture()
 | 
			
		||||
        self._inject_setup_function_fixture()
 | 
			
		||||
        self.session._fixturemanager.parsefactories(self)
 | 
			
		||||
        return super(Module, self).collect()
 | 
			
		||||
 | 
			
		||||
    def _inject_setup_module_fixture(self):
 | 
			
		||||
        """Injects a hidden autouse, module scoped fixture into the collected module object
 | 
			
		||||
        that invokes setUpModule/tearDownModule if either or both are available.
 | 
			
		||||
 | 
			
		||||
        Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
 | 
			
		||||
        other fixtures (#517).
 | 
			
		||||
        """
 | 
			
		||||
        setup_module = _get_non_fixture_func(self.obj, "setUpModule")
 | 
			
		||||
        if setup_module is None:
 | 
			
		||||
            setup_module = _get_non_fixture_func(self.obj, "setup_module")
 | 
			
		||||
 | 
			
		||||
        teardown_module = _get_non_fixture_func(self.obj, "tearDownModule")
 | 
			
		||||
        if teardown_module is None:
 | 
			
		||||
            teardown_module = _get_non_fixture_func(self.obj, "teardown_module")
 | 
			
		||||
 | 
			
		||||
        if setup_module is None and teardown_module is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        @fixtures.fixture(autouse=True, scope="module")
 | 
			
		||||
        def xunit_setup_module_fixture(request):
 | 
			
		||||
            if setup_module is not None:
 | 
			
		||||
                _call_with_optional_argument(setup_module, request.module)
 | 
			
		||||
            yield
 | 
			
		||||
            if teardown_module is not None:
 | 
			
		||||
                _call_with_optional_argument(teardown_module, request.module)
 | 
			
		||||
 | 
			
		||||
        self.obj.__pytest_setup_module = xunit_setup_module_fixture
 | 
			
		||||
 | 
			
		||||
    def _inject_setup_function_fixture(self):
 | 
			
		||||
        """Injects a hidden autouse, function scoped fixture into the collected module object
 | 
			
		||||
        that invokes setup_function/teardown_function if either or both are available.
 | 
			
		||||
 | 
			
		||||
        Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
 | 
			
		||||
        other fixtures (#517).
 | 
			
		||||
        """
 | 
			
		||||
        setup_function = _get_non_fixture_func(self.obj, "setup_function")
 | 
			
		||||
        teardown_function = _get_non_fixture_func(self.obj, "teardown_function")
 | 
			
		||||
        if setup_function is None and teardown_function is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        @fixtures.fixture(autouse=True, scope="function")
 | 
			
		||||
        def xunit_setup_function_fixture(request):
 | 
			
		||||
            if request.instance is not None:
 | 
			
		||||
                # in this case we are bound to an instance, so we need to let
 | 
			
		||||
                # setup_method handle this
 | 
			
		||||
                yield
 | 
			
		||||
                return
 | 
			
		||||
            if setup_function is not None:
 | 
			
		||||
                _call_with_optional_argument(setup_function, request.function)
 | 
			
		||||
            yield
 | 
			
		||||
            if teardown_function is not None:
 | 
			
		||||
                _call_with_optional_argument(teardown_function, request.function)
 | 
			
		||||
 | 
			
		||||
        self.obj.__pytest_setup_function = xunit_setup_function_fixture
 | 
			
		||||
 | 
			
		||||
    def _importtestmodule(self):
 | 
			
		||||
        # we assume we are only called once per module
 | 
			
		||||
        importmode = self.config.getoption("--import-mode")
 | 
			
		||||
| 
						 | 
				
			
			@ -485,19 +543,6 @@ class Module(nodes.File, PyCollector):
 | 
			
		|||
        self.config.pluginmanager.consider_module(mod)
 | 
			
		||||
        return mod
 | 
			
		||||
 | 
			
		||||
    def setup(self):
 | 
			
		||||
        setup_module = _get_xunit_setup_teardown(self.obj, "setUpModule")
 | 
			
		||||
        if setup_module is None:
 | 
			
		||||
            setup_module = _get_xunit_setup_teardown(self.obj, "setup_module")
 | 
			
		||||
        if setup_module is not None:
 | 
			
		||||
            setup_module()
 | 
			
		||||
 | 
			
		||||
        teardown_module = _get_xunit_setup_teardown(self.obj, "tearDownModule")
 | 
			
		||||
        if teardown_module is None:
 | 
			
		||||
            teardown_module = _get_xunit_setup_teardown(self.obj, "teardown_module")
 | 
			
		||||
        if teardown_module is not None:
 | 
			
		||||
            self.addfinalizer(teardown_module)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Package(Module):
 | 
			
		||||
    def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
 | 
			
		||||
| 
						 | 
				
			
			@ -510,6 +555,22 @@ class Package(Module):
 | 
			
		|||
        self._norecursepatterns = session._norecursepatterns
 | 
			
		||||
        self.fspath = fspath
 | 
			
		||||
 | 
			
		||||
    def setup(self):
 | 
			
		||||
        # not using fixtures to call setup_module here because autouse fixtures
 | 
			
		||||
        # from packages are not called automatically (#4085)
 | 
			
		||||
        setup_module = _get_non_fixture_func(self.obj, "setUpModule")
 | 
			
		||||
        if setup_module is None:
 | 
			
		||||
            setup_module = _get_non_fixture_func(self.obj, "setup_module")
 | 
			
		||||
        if setup_module is not None:
 | 
			
		||||
            _call_with_optional_argument(setup_module, self.obj)
 | 
			
		||||
 | 
			
		||||
        teardown_module = _get_non_fixture_func(self.obj, "tearDownModule")
 | 
			
		||||
        if teardown_module is None:
 | 
			
		||||
            teardown_module = _get_non_fixture_func(self.obj, "teardown_module")
 | 
			
		||||
        if teardown_module is not None:
 | 
			
		||||
            func = partial(_call_with_optional_argument, teardown_module, self.obj)
 | 
			
		||||
            self.addfinalizer(func)
 | 
			
		||||
 | 
			
		||||
    def _recurse(self, dirpath):
 | 
			
		||||
        if dirpath.basename == "__pycache__":
 | 
			
		||||
            return False
 | 
			
		||||
| 
						 | 
				
			
			@ -596,8 +657,9 @@ def _get_xunit_setup_teardown(holder, attr_name, param_obj=None):
 | 
			
		|||
    when the callable is called without arguments, defaults to the ``holder`` object.
 | 
			
		||||
    Return ``None`` if a suitable callable is not found.
 | 
			
		||||
    """
 | 
			
		||||
    # TODO: only needed because of Package!
 | 
			
		||||
    param_obj = param_obj if param_obj is not None else holder
 | 
			
		||||
    result = _get_xunit_func(holder, attr_name)
 | 
			
		||||
    result = _get_non_fixture_func(holder, attr_name)
 | 
			
		||||
    if result is not None:
 | 
			
		||||
        arg_count = result.__code__.co_argcount
 | 
			
		||||
        if inspect.ismethod(result):
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +670,19 @@ def _get_xunit_setup_teardown(holder, attr_name, param_obj=None):
 | 
			
		|||
            return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_xunit_func(obj, name):
 | 
			
		||||
def _call_with_optional_argument(func, arg):
 | 
			
		||||
    """Call the given function with the given argument if func accepts one argument, otherwise
 | 
			
		||||
    calls func without arguments"""
 | 
			
		||||
    arg_count = func.__code__.co_argcount
 | 
			
		||||
    if inspect.ismethod(func):
 | 
			
		||||
        arg_count -= 1
 | 
			
		||||
    if arg_count:
 | 
			
		||||
        func(arg)
 | 
			
		||||
    else:
 | 
			
		||||
        func()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_non_fixture_func(obj, name):
 | 
			
		||||
    """Return the attribute from the given object to be used as a setup/teardown
 | 
			
		||||
    xunit-style function, but only if not marked as a fixture to
 | 
			
		||||
    avoid calling it twice.
 | 
			
		||||
| 
						 | 
				
			
			@ -640,18 +714,60 @@ class Class(PyCollector):
 | 
			
		|||
                )
 | 
			
		||||
            )
 | 
			
		||||
            return []
 | 
			
		||||
 | 
			
		||||
        self._inject_setup_class_fixture()
 | 
			
		||||
        self._inject_setup_method_fixture()
 | 
			
		||||
 | 
			
		||||
        return [Instance(name="()", parent=self)]
 | 
			
		||||
 | 
			
		||||
    def setup(self):
 | 
			
		||||
        setup_class = _get_xunit_func(self.obj, "setup_class")
 | 
			
		||||
        if setup_class is not None:
 | 
			
		||||
            setup_class = getimfunc(setup_class)
 | 
			
		||||
            setup_class(self.obj)
 | 
			
		||||
    def _inject_setup_class_fixture(self):
 | 
			
		||||
        """Injects a hidden autouse, class scoped fixture into the collected class object
 | 
			
		||||
        that invokes setup_class/teardown_class if either or both are available.
 | 
			
		||||
 | 
			
		||||
        fin_class = getattr(self.obj, "teardown_class", None)
 | 
			
		||||
        if fin_class is not None:
 | 
			
		||||
            fin_class = getimfunc(fin_class)
 | 
			
		||||
            self.addfinalizer(lambda: fin_class(self.obj))
 | 
			
		||||
        Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
 | 
			
		||||
        other fixtures (#517).
 | 
			
		||||
        """
 | 
			
		||||
        setup_class = _get_non_fixture_func(self.obj, "setup_class")
 | 
			
		||||
        teardown_class = getattr(self.obj, "teardown_class", None)
 | 
			
		||||
        if setup_class is None and teardown_class is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        @fixtures.fixture(autouse=True, scope="class")
 | 
			
		||||
        def xunit_setup_class_fixture(cls):
 | 
			
		||||
            if setup_class is not None:
 | 
			
		||||
                func = getimfunc(setup_class)
 | 
			
		||||
                _call_with_optional_argument(func, self.obj)
 | 
			
		||||
            yield
 | 
			
		||||
            if teardown_class is not None:
 | 
			
		||||
                func = getimfunc(teardown_class)
 | 
			
		||||
                _call_with_optional_argument(func, self.obj)
 | 
			
		||||
 | 
			
		||||
        self.obj.__pytest_setup_class = xunit_setup_class_fixture
 | 
			
		||||
 | 
			
		||||
    def _inject_setup_method_fixture(self):
 | 
			
		||||
        """Injects a hidden autouse, function scoped fixture into the collected class object
 | 
			
		||||
        that invokes setup_method/teardown_method if either or both are available.
 | 
			
		||||
 | 
			
		||||
        Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
 | 
			
		||||
        other fixtures (#517).
 | 
			
		||||
        """
 | 
			
		||||
        setup_method = _get_non_fixture_func(self.obj, "setup_method")
 | 
			
		||||
        teardown_method = getattr(self.obj, "teardown_method", None)
 | 
			
		||||
        if setup_method is None and teardown_method is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        @fixtures.fixture(autouse=True, scope="function")
 | 
			
		||||
        def xunit_setup_method_fixture(self, request):
 | 
			
		||||
            method = request.function
 | 
			
		||||
            if setup_method is not None:
 | 
			
		||||
                func = getattr(self, "setup_method")
 | 
			
		||||
                _call_with_optional_argument(func, method)
 | 
			
		||||
            yield
 | 
			
		||||
            if teardown_method is not None:
 | 
			
		||||
                func = getattr(self, "teardown_method")
 | 
			
		||||
                _call_with_optional_argument(func, method)
 | 
			
		||||
 | 
			
		||||
        self.obj.__pytest_setup_method = xunit_setup_method_fixture
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Instance(PyCollector):
 | 
			
		||||
| 
						 | 
				
			
			@ -678,29 +794,9 @@ class FunctionMixin(PyobjMixin):
 | 
			
		|||
 | 
			
		||||
    def setup(self):
 | 
			
		||||
        """ perform setup for this test function. """
 | 
			
		||||
        if hasattr(self, "_preservedparent"):
 | 
			
		||||
            obj = self._preservedparent
 | 
			
		||||
        elif isinstance(self.parent, Instance):
 | 
			
		||||
            obj = self.parent.newinstance()
 | 
			
		||||
        if isinstance(self.parent, Instance):
 | 
			
		||||
            self.parent.newinstance()
 | 
			
		||||
            self.obj = self._getobj()
 | 
			
		||||
        else:
 | 
			
		||||
            obj = self.parent.obj
 | 
			
		||||
        if inspect.ismethod(self.obj):
 | 
			
		||||
            setup_name = "setup_method"
 | 
			
		||||
            teardown_name = "teardown_method"
 | 
			
		||||
        else:
 | 
			
		||||
            setup_name = "setup_function"
 | 
			
		||||
            teardown_name = "teardown_function"
 | 
			
		||||
        setup_func_or_method = _get_xunit_setup_teardown(
 | 
			
		||||
            obj, setup_name, param_obj=self.obj
 | 
			
		||||
        )
 | 
			
		||||
        if setup_func_or_method is not None:
 | 
			
		||||
            setup_func_or_method()
 | 
			
		||||
        teardown_func_or_method = _get_xunit_setup_teardown(
 | 
			
		||||
            obj, teardown_name, param_obj=self.obj
 | 
			
		||||
        )
 | 
			
		||||
        if teardown_func_or_method is not None:
 | 
			
		||||
            self.addfinalizer(teardown_func_or_method)
 | 
			
		||||
 | 
			
		||||
    def _prunetraceback(self, excinfo):
 | 
			
		||||
        if hasattr(self, "_obj") and not self.config.option.fulltrace:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import sys
 | 
			
		|||
import traceback
 | 
			
		||||
 | 
			
		||||
import _pytest._code
 | 
			
		||||
import pytest
 | 
			
		||||
from _pytest.compat import getimfunc
 | 
			
		||||
from _pytest.config import hookimpl
 | 
			
		||||
from _pytest.outcomes import fail
 | 
			
		||||
| 
						 | 
				
			
			@ -32,24 +33,18 @@ class UnitTestCase(Class):
 | 
			
		|||
    # to declare that our children do not support funcargs
 | 
			
		||||
    nofuncargs = True
 | 
			
		||||
 | 
			
		||||
    def setup(self):
 | 
			
		||||
        cls = self.obj
 | 
			
		||||
        if getattr(cls, "__unittest_skip__", False):
 | 
			
		||||
            return  # skipped
 | 
			
		||||
        setup = getattr(cls, "setUpClass", None)
 | 
			
		||||
        if setup is not None:
 | 
			
		||||
            setup()
 | 
			
		||||
        teardown = getattr(cls, "tearDownClass", None)
 | 
			
		||||
        if teardown is not None:
 | 
			
		||||
            self.addfinalizer(teardown)
 | 
			
		||||
        super(UnitTestCase, self).setup()
 | 
			
		||||
 | 
			
		||||
    def collect(self):
 | 
			
		||||
        from unittest import TestLoader
 | 
			
		||||
 | 
			
		||||
        cls = self.obj
 | 
			
		||||
        if not getattr(cls, "__test__", True):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        skipped = getattr(cls, "__unittest_skip__", False)
 | 
			
		||||
        if not skipped:
 | 
			
		||||
            self._inject_setup_teardown_fixtures(cls)
 | 
			
		||||
            self._inject_setup_class_fixture()
 | 
			
		||||
 | 
			
		||||
        self.session._fixturemanager.parsefactories(self, unittest=True)
 | 
			
		||||
        loader = TestLoader()
 | 
			
		||||
        foundsomething = False
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +63,44 @@ class UnitTestCase(Class):
 | 
			
		|||
                if ut is None or runtest != ut.TestCase.runTest:
 | 
			
		||||
                    yield TestCaseFunction("runTest", parent=self)
 | 
			
		||||
 | 
			
		||||
    def _inject_setup_teardown_fixtures(self, cls):
 | 
			
		||||
        """Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding
 | 
			
		||||
        teardown functions (#517)"""
 | 
			
		||||
        class_fixture = _make_xunit_fixture(
 | 
			
		||||
            cls, "setUpClass", "tearDownClass", scope="class", pass_self=False
 | 
			
		||||
        )
 | 
			
		||||
        if class_fixture:
 | 
			
		||||
            cls.__pytest_class_setup = class_fixture
 | 
			
		||||
 | 
			
		||||
        method_fixture = _make_xunit_fixture(
 | 
			
		||||
            cls, "setup_method", "teardown_method", scope="function", pass_self=True
 | 
			
		||||
        )
 | 
			
		||||
        if method_fixture:
 | 
			
		||||
            cls.__pytest_method_setup = method_fixture
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _make_xunit_fixture(obj, setup_name, teardown_name, scope, pass_self):
 | 
			
		||||
    setup = getattr(obj, setup_name, None)
 | 
			
		||||
    teardown = getattr(obj, teardown_name, None)
 | 
			
		||||
    if setup is None and teardown is None:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    @pytest.fixture(scope=scope, autouse=True)
 | 
			
		||||
    def fixture(self, request):
 | 
			
		||||
        if setup is not None:
 | 
			
		||||
            if pass_self:
 | 
			
		||||
                setup(self, request.function)
 | 
			
		||||
            else:
 | 
			
		||||
                setup()
 | 
			
		||||
        yield
 | 
			
		||||
        if teardown is not None:
 | 
			
		||||
            if pass_self:
 | 
			
		||||
                teardown(self, request.function)
 | 
			
		||||
            else:
 | 
			
		||||
                teardown()
 | 
			
		||||
 | 
			
		||||
    return fixture
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestCaseFunction(Function):
 | 
			
		||||
    nofuncargs = True
 | 
			
		||||
| 
						 | 
				
			
			@ -77,9 +110,6 @@ class TestCaseFunction(Function):
 | 
			
		|||
    def setup(self):
 | 
			
		||||
        self._testcase = self.parent.obj(self.name)
 | 
			
		||||
        self._fix_unittest_skip_decorator()
 | 
			
		||||
        self._obj = getattr(self._testcase, self.name)
 | 
			
		||||
        if hasattr(self._testcase, "setup_method"):
 | 
			
		||||
            self._testcase.setup_method(self._obj)
 | 
			
		||||
        if hasattr(self, "_request"):
 | 
			
		||||
            self._request._fillfixtures()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -97,11 +127,7 @@ class TestCaseFunction(Function):
 | 
			
		|||
            setattr(self._testcase, "__name__", self.name)
 | 
			
		||||
 | 
			
		||||
    def teardown(self):
 | 
			
		||||
        if hasattr(self._testcase, "teardown_method"):
 | 
			
		||||
            self._testcase.teardown_method(self._obj)
 | 
			
		||||
        # Allow garbage collection on TestCase instance attributes.
 | 
			
		||||
        self._testcase = None
 | 
			
		||||
        self._obj = None
 | 
			
		||||
 | 
			
		||||
    def startTest(self, testcase):
 | 
			
		||||
        pass
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -240,9 +240,6 @@ class TestClass(object):
 | 
			
		|||
        assert result.ret == EXIT_NOTESTSCOLLECTED
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.filterwarnings(
 | 
			
		||||
    "ignore:usage of Generator.Function is deprecated, please use pytest.Function instead"
 | 
			
		||||
)
 | 
			
		||||
class TestFunction(object):
 | 
			
		||||
    def test_getmodulecollector(self, testdir):
 | 
			
		||||
        item = testdir.getitem("def test_func(): pass")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1226,6 +1226,45 @@ class TestFixtureUsages(object):
 | 
			
		|||
        values = reprec.getcalls("pytest_runtest_call")[0].item.module.values
 | 
			
		||||
        assert values == [1, 2, 10, 20]
 | 
			
		||||
 | 
			
		||||
    def test_setup_functions_as_fixtures(self, testdir):
 | 
			
		||||
        """Ensure setup_* methods obey fixture scope rules (#517, #3094)."""
 | 
			
		||||
        testdir.makepyfile(
 | 
			
		||||
            """
 | 
			
		||||
            import pytest
 | 
			
		||||
 | 
			
		||||
            DB_INITIALIZED = None
 | 
			
		||||
 | 
			
		||||
            @pytest.yield_fixture(scope="session", autouse=True)
 | 
			
		||||
            def db():
 | 
			
		||||
                global DB_INITIALIZED
 | 
			
		||||
                DB_INITIALIZED = True
 | 
			
		||||
                yield
 | 
			
		||||
                DB_INITIALIZED = False
 | 
			
		||||
 | 
			
		||||
            def setup_module():
 | 
			
		||||
                assert DB_INITIALIZED
 | 
			
		||||
 | 
			
		||||
            def teardown_module():
 | 
			
		||||
                assert DB_INITIALIZED
 | 
			
		||||
 | 
			
		||||
            class TestClass(object):
 | 
			
		||||
 | 
			
		||||
                def setup_method(self, method):
 | 
			
		||||
                    assert DB_INITIALIZED
 | 
			
		||||
 | 
			
		||||
                def teardown_method(self, method):
 | 
			
		||||
                    assert DB_INITIALIZED
 | 
			
		||||
 | 
			
		||||
                def test_printer_1(self):
 | 
			
		||||
                    pass
 | 
			
		||||
 | 
			
		||||
                def test_printer_2(self):
 | 
			
		||||
                    pass
 | 
			
		||||
        """
 | 
			
		||||
        )
 | 
			
		||||
        result = testdir.runpytest()
 | 
			
		||||
        result.stdout.fnmatch_lines(["* 2 passed in *"])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestFixtureManagerParseFactories(object):
 | 
			
		||||
    @pytest.fixture
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue