From 6cb3281ddde67eb90afa55793bf0bff433d098ec Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 18 Sep 2012 14:00:47 +0200 Subject: [PATCH] allow factory/setup-markers on classes, using their respective __init__ methods which can use the funcarg mechanism --- _pytest/python.py | 9 ++++++--- doc/en/funcargs.txt | 18 +++++++----------- testing/test_python.py | 25 +++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index c490828c0..d77b35768 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1507,9 +1507,12 @@ class FactoryDef: def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames - argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0] - if startindex is None: - startindex = py.std.inspect.ismethod(function) and 1 or 0 + if inspect.isclass(function): + function = function.__init__ + startindex = 1 + elif startindex is None: + startindex = inspect.ismethod(function) and 1 or 0 + argnames = inspect.getargs(py.code.getrawcode(function))[0] defaults = getattr(function, 'func_defaults', getattr(function, '__defaults__', None)) or () numdefaults = len(defaults) diff --git a/doc/en/funcargs.txt b/doc/en/funcargs.txt index 546b18e0b..54cc81613 100644 --- a/doc/en/funcargs.txt +++ b/doc/en/funcargs.txt @@ -389,19 +389,16 @@ object ``app`` and stick the ``smtp`` resource into it like this:: import pytest - class App: + @pytest.factory(scope="module") + class app: def __init__(self, smtp): self.smtp = smtp - @pytest.factory(scope="module") - def app(smtp): - return App(smtp) - def test_exists(app): assert app.smtp -Here we define the factory local to the test module and make it access -the ``smtp`` resource by listing it as an input parameter. Let's run this:: +Here we declare an ``app`` class to be a factory and have its init-method +use the previously defined ``smtp`` resource. Let's run it:: $ py.test -v test_appsetup.py =========================== test session starts ============================ @@ -418,7 +415,7 @@ the ``smtp`` resource by listing it as an input parameter. Let's run this:: Due to the parametrization of ``smtp`` the test will run twice with two different ``App`` instances and respective smtp servers. There is no need for the ``app`` factory to be aware of the parametrization. Note -that the ``app`` factory has a scope of ``module`` whereas it uses the +that the ``app`` factory has a scope of ``module`` but uses the session-scoped ``smtp`` object: it is fine for factories to use "broader" scoped resources but not the other way round. A session-scoped resource could not use a module-scoped resource in a @@ -498,8 +495,8 @@ Let's run the tests in verbose mode and with looking at the print-output:: fin mod2 You can see that the parametrized module-scoped ``modarg`` resource caused -a re-ordering of test execution. The finalizer for the ``mod1`` parametrized -resource was executed before the ``mod2`` resource was setup. +an ordering of test execution that lead to the fewest possible "active" resources. The finalizer for the ``mod1`` parametrized resource was executed +before the ``mod2`` resource was setup. .. currentmodule:: _pytest.python .. _`request`: @@ -520,7 +517,6 @@ The ``request`` object may be received by `@pytest.factory`_ or * to add finalizers/teardowns to be invoked when the last test of the requesting test context executes - .. autoclass:: _pytest.python.FuncargRequest() :members: diff --git a/testing/test_python.py b/testing/test_python.py index 9a55565a5..9a159c847 100644 --- a/testing/test_python.py +++ b/testing/test_python.py @@ -535,6 +535,11 @@ 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 TestFillFuncArgs: def test_fillfuncargs_exposed(self): # used by oejskit @@ -1727,6 +1732,26 @@ class TestFuncargFactory: ]) + def test_factory_setup_as_classes(self, testdir): + testdir.makepyfile(""" + import pytest + class arg1: + def __init__(self, request): + self.x = 1 + arg1 = pytest.factory()(arg1) + + class MySetup: + def __init__(self, request, arg1): + request.instance.arg1 = arg1 + pytest.setup()(MySetup) + + class TestClass: + def test_method(self): + assert self.arg1.x == 1 + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) + class TestResourceIntegrationFunctional: def test_parametrize_with_ids(self, testdir):