From df643f65f073c24278e080a8cd6d6be4b7da1a7a Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 8 Oct 2012 11:22:31 +0200 Subject: [PATCH] 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. --- _pytest/python.py | 10 +++++----- doc/en/fixture.txt | 29 ++++++++++++++++------------- testing/test_python.py | 17 +++-------------- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 3a00c75f5..04a0d6d47 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -17,6 +17,8 @@ class FixtureFunctionMarker: self.autoactive = autoactive def __call__(self, function): + if inspect.isclass(function): + raise ValueError("class fixtures not supported (may be in the future)") function._pytestfixturefunction = self return function @@ -43,7 +45,7 @@ def fixture(scope="function", params=None, autoactive=False): can see it. If False (the default) then an explicit 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 return FixtureFunctionMarker("function", params, autoactive)(scope) else: @@ -1563,10 +1565,8 @@ class FixtureDef: def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames - if inspect.isclass(function): - function = function.__init__ - startindex = 1 - elif startindex is None: + #assert not inspect.isclass(function) + if startindex is None: startindex = inspect.ismethod(function) and 1 or 0 argnames = inspect.getargs(py.code.getrawcode(function))[0] defaults = getattr(function, 'func_defaults', diff --git a/doc/en/fixture.txt b/doc/en/fixture.txt index dd1e4564c..1d1da720e 100644 --- a/doc/en/fixture.txt +++ b/doc/en/fixture.txt @@ -569,8 +569,7 @@ self-contained implementation of this idea:: import pytest - @pytest.fixture(scope="module") - class db: + class DB: def __init__(self): self.intransaction = [] def begin(self, name): @@ -578,6 +577,10 @@ self-contained implementation of this idea:: def rollback(self): self.intransaction.pop() + @pytest.fixture(scope="module") + def db(): + return DB() + class TestClass: @pytest.fixture(autoactive=True) def transact(self, request, db): @@ -590,9 +593,9 @@ self-contained implementation of this idea:: def test_method2(self, db): assert db.intransaction == ["test_method2"] -The class-level ``transact`` fixture is marked with *autoactive=true* which implies -that all test methods in the class will use this fixture without a need to -specify it. +The class-level ``transact`` fixture is marked with *autoactive=true* +which implies that all test methods in the class will use this fixture +without a need to specify it. 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 any work and avoid expensive imports or computation otherwise. -Note that the above ``transact`` fixture may very well be something that -you want to make available in your project but which requires an explicit using -reference to have it activated. The canonical way to do that is to put -the transact definition into a conftest.py file without using -``autoactive``:: +Note that the above ``transact`` fixture may very well be a fixture that +you want to make available in your project without having it generally +active. The canonical way to do that is to put the transact definition +into a conftest.py file without using ``autoactive``:: # content of conftest.py @pytest.fixture() @@ -626,15 +628,16 @@ the transact definition into a conftest.py file without using db.begin() 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") class TestClass: def test_method1(self): ... -While all test methods in this TestClass will use the transaction -fixture, other test classes or function will not do so without a marker or funcarg. +All test methods in this TestClass will use the transaction fixture while +other test classes or functions will not do so unless they also add +a ``transact`` reference. controlled visibility of fixture functions ---------------------------------------------------- diff --git a/testing/test_python.py b/testing/test_python.py index e17058ac2..7c09a216c 100644 --- a/testing/test_python.py +++ b/testing/test_python.py @@ -547,10 +547,6 @@ def test_getfuncargnames(): if sys.version_info < (3,0): assert funcargs.getfuncargnames(A.f) == ['arg1'] - class A: - def __init__(self, x): - pass - assert funcargs.getfuncargnames(A) == ["x"] class TestFillFixtures: def test_fillfuncargs_exposed(self): @@ -1803,7 +1799,7 @@ class TestFixtureUsages: *fixture*'missing'*not found* """) - def test_factory_setup_as_classes(self, testdir): + def test_factory_setup_as_classes_fails(self, testdir): testdir.makepyfile(""" import pytest class arg1: @@ -1811,17 +1807,10 @@ class TestFixtureUsages: self.x = 1 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.assertoutcome(passed=1) + l = reprec.getfailedcollections() + assert len(l) == 1 def test_request_can_be_overridden(self, testdir): testdir.makepyfile("""