remove support for @pytest.fixture on classes, to be reserved for future use:

Fixture-classes could offer setup/teardown/addoption/configure methods
and provide higher level support.  Preliminary allowing it to work on classes
may make introducing it harder.
This commit is contained in:
holger krekel 2012-10-08 11:22:31 +02:00
parent d630d02c5b
commit df643f65f0
3 changed files with 24 additions and 32 deletions

View File

@ -17,6 +17,8 @@ class FixtureFunctionMarker:
self.autoactive = autoactive self.autoactive = autoactive
def __call__(self, function): def __call__(self, function):
if inspect.isclass(function):
raise ValueError("class fixtures not supported (may be in the future)")
function._pytestfixturefunction = self function._pytestfixturefunction = self
return function return function
@ -43,7 +45,7 @@ def fixture(scope="function", params=None, autoactive=False):
can see it. If False (the default) then an explicit can see it. If False (the default) then an explicit
reference is needed to activate the fixture. reference is needed to activate the fixture.
""" """
if hasattr(scope, "__call__") and params is None and autoactive == False: if py.builtin.callable(scope) and params is None and autoactive == False:
# direct decoration # direct decoration
return FixtureFunctionMarker("function", params, autoactive)(scope) return FixtureFunctionMarker("function", params, autoactive)(scope)
else: else:
@ -1563,10 +1565,8 @@ class FixtureDef:
def getfuncargnames(function, startindex=None): def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames # XXX merge with main.py's varnames
if inspect.isclass(function): #assert not inspect.isclass(function)
function = function.__init__ if startindex is None:
startindex = 1
elif startindex is None:
startindex = inspect.ismethod(function) and 1 or 0 startindex = inspect.ismethod(function) and 1 or 0
argnames = inspect.getargs(py.code.getrawcode(function))[0] argnames = inspect.getargs(py.code.getrawcode(function))[0]
defaults = getattr(function, 'func_defaults', defaults = getattr(function, 'func_defaults',

View File

@ -569,8 +569,7 @@ self-contained implementation of this idea::
import pytest import pytest
@pytest.fixture(scope="module") class DB:
class db:
def __init__(self): def __init__(self):
self.intransaction = [] self.intransaction = []
def begin(self, name): def begin(self, name):
@ -578,6 +577,10 @@ self-contained implementation of this idea::
def rollback(self): def rollback(self):
self.intransaction.pop() self.intransaction.pop()
@pytest.fixture(scope="module")
def db():
return DB()
class TestClass: class TestClass:
@pytest.fixture(autoactive=True) @pytest.fixture(autoactive=True)
def transact(self, request, db): def transact(self, request, db):
@ -590,9 +593,9 @@ self-contained implementation of this idea::
def test_method2(self, db): def test_method2(self, db):
assert db.intransaction == ["test_method2"] assert db.intransaction == ["test_method2"]
The class-level ``transact`` fixture is marked with *autoactive=true* which implies The class-level ``transact`` fixture is marked with *autoactive=true*
that all test methods in the class will use this fixture without a need to which implies that all test methods in the class will use this fixture
specify it. without a need to specify it.
If we run it, we get two passing tests:: If we run it, we get two passing tests::
@ -614,11 +617,10 @@ And here is how autoactive fixtures work in other scopes:
a global fixture should always quickly determine if it should do a global fixture should always quickly determine if it should do
any work and avoid expensive imports or computation otherwise. any work and avoid expensive imports or computation otherwise.
Note that the above ``transact`` fixture may very well be something that Note that the above ``transact`` fixture may very well be a fixture that
you want to make available in your project but which requires an explicit using you want to make available in your project without having it generally
reference to have it activated. The canonical way to do that is to put active. The canonical way to do that is to put the transact definition
the transact definition into a conftest.py file without using into a conftest.py file without using ``autoactive``::
``autoactive``::
# content of conftest.py # content of conftest.py
@pytest.fixture() @pytest.fixture()
@ -626,15 +628,16 @@ the transact definition into a conftest.py file without using
db.begin() db.begin()
request.addfinalizer(db.rollback) request.addfinalizer(db.rollback)
and then have a TestClass using it by declaring the need:: and then e.g. have a TestClass using it by declaring the need::
@pytest.mark.usefixtures("transact") @pytest.mark.usefixtures("transact")
class TestClass: class TestClass:
def test_method1(self): def test_method1(self):
... ...
While all test methods in this TestClass will use the transaction All test methods in this TestClass will use the transaction fixture while
fixture, other test classes or function will not do so without a marker or funcarg. other test classes or functions will not do so unless they also add
a ``transact`` reference.
controlled visibility of fixture functions controlled visibility of fixture functions
---------------------------------------------------- ----------------------------------------------------

View File

@ -547,10 +547,6 @@ def test_getfuncargnames():
if sys.version_info < (3,0): if sys.version_info < (3,0):
assert funcargs.getfuncargnames(A.f) == ['arg1'] assert funcargs.getfuncargnames(A.f) == ['arg1']
class A:
def __init__(self, x):
pass
assert funcargs.getfuncargnames(A) == ["x"]
class TestFillFixtures: class TestFillFixtures:
def test_fillfuncargs_exposed(self): def test_fillfuncargs_exposed(self):
@ -1803,7 +1799,7 @@ class TestFixtureUsages:
*fixture*'missing'*not found* *fixture*'missing'*not found*
""") """)
def test_factory_setup_as_classes(self, testdir): def test_factory_setup_as_classes_fails(self, testdir):
testdir.makepyfile(""" testdir.makepyfile("""
import pytest import pytest
class arg1: class arg1:
@ -1811,17 +1807,10 @@ class TestFixtureUsages:
self.x = 1 self.x = 1
arg1 = pytest.fixture()(arg1) arg1 = pytest.fixture()(arg1)
class MySetup:
def __init__(self, request, arg1):
request.instance.arg1 = arg1
pytest.fixture(autoactive=True)(MySetup)
class TestClass:
def test_method(self):
assert self.arg1.x == 1
""") """)
reprec = testdir.inline_run() reprec = testdir.inline_run()
reprec.assertoutcome(passed=1) l = reprec.getfailedcollections()
assert len(l) == 1
def test_request_can_be_overridden(self, testdir): def test_request_can_be_overridden(self, testdir):
testdir.makepyfile(""" testdir.makepyfile("""