From f358fe7154f4d65b885942d36c9ac866cd07d228 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Fri, 20 Jul 2012 14:16:46 +0200 Subject: [PATCH] extend Metafunc and write a pytest_generate_tests hook on the funcarg manager which discovers factories --- _pytest/main.py | 21 ++++++++++++++++++--- _pytest/python.py | 11 ++++------- testing/test_python.py | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/_pytest/main.py b/_pytest/main.py index 842156cc7..72715aa1d 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -443,6 +443,19 @@ class FuncargManager: for plugin in plugins: self.pytest_plugin_registered(plugin) + def pytest_generate_tests(self, metafunc): + for argname in metafunc.funcargnames: + faclist = self.getfactorylist(argname, metafunc.parentid, + metafunc.function, raising=False) + if faclist is None: + continue # will raise at setup time + for fac in faclist: + marker = getattr(fac, "funcarg", None) + if marker is not None: + params = marker.kwargs.get("params") + if params is not None: + metafunc.parametrize(argname, params, indirect=True) + def _parsefactories(self, holderobj, nodeid): if holderobj in self._holderobjseen: return @@ -456,12 +469,14 @@ class FuncargManager: obj = getattr(holderobj, name) faclist.append((nodeid, obj)) - def getfactorylist(self, argname, nodeid, function): + def getfactorylist(self, argname, nodeid, function, raising=True): try: factorydef = self.arg2facspec[argname] except KeyError: - self._raiselookupfailed(argname, function, nodeid) - return self._matchfactories(factorydef, nodeid) + if raising: + self._raiselookupfailed(argname, function, nodeid) + else: + return self._matchfactories(factorydef, nodeid) def _matchfactories(self, factorydef, nodeid): l = [] diff --git a/_pytest/python.py b/_pytest/python.py index 94531bfe0..5f9da87f3 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -256,7 +256,7 @@ class PyCollector(PyobjMixin, pytest.Collector): clscol = self.getparent(Class) cls = clscol and clscol.obj or None transfer_markers(funcobj, cls, module) - metafunc = Metafunc(funcobj, config=self.config, + metafunc = Metafunc(funcobj, parentid=self.nodeid, config=self.config, cls=cls, module=module) gentesthook = self.config.hook.pytest_generate_tests extra = [module] @@ -555,10 +555,12 @@ class CallSpec2(object): class Metafunc: - def __init__(self, function, config=None, cls=None, module=None): + def __init__(self, function, config=None, cls=None, module=None, + parentid=""): self.config = config self.module = module self.function = function + self.parentid = parentid self.funcargnames = getfuncargnames(function, startindex=int(cls is not None)) self.cls = cls @@ -885,11 +887,6 @@ class FuncargRequest: self.funcargnames = getfuncargnames(self.function) self.parentid = pyfuncitem.parent.nodeid - def _discoverfactories(self): - for argname in self.funcargnames: - if argname not in self._funcargs: - self._getfaclist(argname) - def _getfaclist(self, argname): faclist = self._name2factory.get(argname, None) if faclist is None: diff --git a/testing/test_python.py b/testing/test_python.py index 8d4b810dc..f3316f31e 100644 --- a/testing/test_python.py +++ b/testing/test_python.py @@ -989,6 +989,7 @@ class TestMetafunc: def test_parametrize_functional(self, testdir): testdir.makepyfile(""" def pytest_generate_tests(metafunc): + assert "test_parametrize_functional" in metafunc.parentid metafunc.parametrize('x', [1,2], indirect=True) metafunc.parametrize('y', [2]) def pytest_funcarg__x(request): @@ -1680,3 +1681,20 @@ class TestFuncargManager: """) reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=1) + +class TestFuncargMarker: + def test_parametrize(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.funcarg(params=["a", "b", "c"]) + def pytest_funcarg__arg(request): + return request.param + l = [] + def test_param(arg): + l.append(arg) + def test_result(): + assert l == list("abc") + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=4) +