2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/changeset/4d9f48622c63/ changeset: 4d9f48622c63 user: hpk42 date: 2012-08-13 12:58:08 summary: fix/update some docs to work with @pytest.factory instead of pytest_funcarg__ naming. affected #: 4 files diff -r 90a3b3d49cebb9b6484251b7c7f6df1c317305d9 -r 4d9f48622c63733d4d67b436d40bdb14fb1ca037 doc/en/example/costlysetup/conftest.py --- a/doc/en/example/costlysetup/conftest.py +++ b/doc/en/example/costlysetup/conftest.py @@ -1,10 +1,11 @@ -def pytest_funcarg__setup(request): - return request.cached_setup( - setup=lambda: CostlySetup(), - teardown=lambda costlysetup: costlysetup.finalize(), - scope="session", - ) +import pytest + +@pytest.factory("session") +def setup(testcontext): + setup = CostlySetup() + testcontext.addfinalizer(setup.finalize) + return setup class CostlySetup: def __init__(self): diff -r 90a3b3d49cebb9b6484251b7c7f6df1c317305d9 -r 4d9f48622c63733d4d67b436d40bdb14fb1ca037 doc/en/example/multipython.py --- a/doc/en/example/multipython.py +++ b/doc/en/example/multipython.py @@ -5,29 +5,14 @@ import py, pytest pythonlist = ['python2.4', 'python2.5', 'python2.6', 'python2.7', 'python2.8'] +@pytest.factory(params=pythonlist) +def python1(testcontext, tmpdir): + picklefile = tmpdir.join("data.pickle") + return Python(testcontext.param, picklefile) -def pytest_generate_tests(metafunc): - # we parametrize all "python1" and "python2" arguments to iterate - # over the python interpreters of our list above - the actual - # setup and lookup of interpreters in the python1/python2 factories - # respectively. - for arg in metafunc.funcargnames: - if arg in ("python1", "python2"): - metafunc.parametrize(arg, pythonlist, indirect=True) - -@pytest.mark.parametrize("obj", [42, {}, {1:3},]) -def test_basic_objects(python1, python2, obj): - python1.dumps(obj) - python2.load_and_is_true("obj == %s" % obj) - -def pytest_funcarg__python1(request): - tmpdir = request.getfuncargvalue("tmpdir") - picklefile = tmpdir.join("data.pickle") - return Python(request.param, picklefile) - -def pytest_funcarg__python2(request): - python1 = request.getfuncargvalue("python1") - return Python(request.param, python1.picklefile) +@pytest.factory(params=pythonlist) +def python2(testcontext, python1): + return Python(testcontext.param, python1.picklefile) class Python: def __init__(self, version, picklefile): @@ -58,3 +43,8 @@ """ % (str(self.picklefile), expression))) print (loadfile) py.process.cmdexec("%s %s" %(self.pythonpath, loadfile)) + +@pytest.mark.parametrize("obj", [42, {}, {1:3},]) +def test_basic_objects(python1, python2, obj): + python1.dumps(obj) + python2.load_and_is_true("obj == %s" % obj) diff -r 90a3b3d49cebb9b6484251b7c7f6df1c317305d9 -r 4d9f48622c63733d4d67b436d40bdb14fb1ca037 doc/en/faq.txt --- a/doc/en/faq.txt +++ b/doc/en/faq.txt @@ -123,6 +123,11 @@ source code and safely find all factory functions for the ``MYARG`` function argument. +.. note:: + + With pytest-2.3 you can use the :ref:`@pytest.factory` decorator + to mark a function as a funcarg factory. + .. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration Can I yield multiple values from a funcarg factory function? @@ -141,8 +146,12 @@ policy - in real-world examples some combinations often should not run. -Use the `pytest_generate_tests`_ hook to solve both issues -and implement the `parametrization scheme of your choice`_. +However, with pytest-2.3 you can use the :ref:`@pytest.factory` decorator +and specify ``params`` so that all tests depending on the factory-created +resource will run multiple times with different parameters. + +You can also use the `pytest_generate_tests`_ hook to +implement the `parametrization scheme of your choice`_. .. _`pytest_generate_tests`: test/funcargs.html#parametrizing-tests .. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ diff -r 90a3b3d49cebb9b6484251b7c7f6df1c317305d9 -r 4d9f48622c63733d4d67b436d40bdb14fb1ca037 doc/en/funcarg_compare.txt --- a/doc/en/funcarg_compare.txt +++ b/doc/en/funcarg_compare.txt @@ -88,7 +88,7 @@ sets. pytest-2.3 introduces a decorator for use on the factory itself:: @pytest.factory(params=["mysql", "pg"]) - def pytest_funcarg__db(testcontext): + def db(testcontext): ... # use testcontext.param Here the factory will be invoked twice (with the respective "mysql" @@ -105,7 +105,7 @@ Of course it's perfectly fine to combine parametrization and scoping:: @pytest.factory(scope="session", params=["mysql", "pg"]) - def pytest_funcarg__db(testcontext): + def db(testcontext): if testcontext.param == "mysql": db = MySQL() elif testcontext.param == "pg": @@ -137,7 +137,9 @@ def pytest_funcarg__db(request): ... -It is recommended to use the resource decorator, however. + +But it is then not possible to define scoping and parametrization. +It is thus recommended to use the factory decorator. solving per-session setup / the new @setup marker https://bitbucket.org/hpk42/pytest/changeset/57b9e4d9bdb2/ changeset: 57b9e4d9bdb2 user: hpk42 date: 2012-08-13 13:37:14 summary: fix issue172 so that @pytest.setup marked setup_module/function... functions are not called twice. Also fix ordering to that broader scoped setup functions are executed first. affected #: 3 files diff -r 4d9f48622c63733d4d67b436d40bdb14fb1ca037 -r 57b9e4d9bdb29039856691c16a2d7b5696d0eb89 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ Changes between 2.2.4 and 2.3.0.dev ----------------------------------- +- fix issue172 duplicate call of pytest.setup-decoratored setup_module + functions - fix junitxml=path construction so that if tests change the current working directory and the path is a relative path it is constructed correctly from the original current working dir. diff -r 4d9f48622c63733d4d67b436d40bdb14fb1ca037 -r 57b9e4d9bdb29039856691c16a2d7b5696d0eb89 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -363,24 +363,26 @@ return mod def setup(self): - if hasattr(self.obj, 'setup_module'): + setup_module = xunitsetup(self.obj, "setup_module") + if setup_module is not None: #XXX: nose compat hack, move to nose plugin # if it takes a positional arg, its probably a pytest style one # so we pass the current module object - if inspect.getargspec(self.obj.setup_module)[0]: - self.obj.setup_module(self.obj) + if inspect.getargspec(setup_module)[0]: + setup_module(self.obj) else: - self.obj.setup_module() + setup_module() def teardown(self): - if hasattr(self.obj, 'teardown_module'): + teardown_module = xunitsetup(self.obj, 'teardown_module') + if teardown_module is not None: #XXX: nose compat hack, move to nose plugin # if it takes a positional arg, its probably a py.test style one # so we pass the current module object - if inspect.getargspec(self.obj.teardown_module)[0]: - self.obj.teardown_module(self.obj) + if inspect.getargspec(teardown_module)[0]: + teardown_module(self.obj) else: - self.obj.teardown_module() + teardown_module() class Class(PyCollector): """ Collector for test methods. """ @@ -388,14 +390,14 @@ return [self._getcustomclass("Instance")(name="()", parent=self)] def setup(self): - setup_class = getattr(self.obj, 'setup_class', None) + setup_class = xunitsetup(self.obj, 'setup_class') if setup_class is not None: setup_class = getattr(setup_class, 'im_func', setup_class) setup_class = getattr(setup_class, '__func__', setup_class) setup_class(self.obj) def teardown(self): - teardown_class = getattr(self.obj, 'teardown_class', None) + teardown_class = xunitsetup(self.obj, 'teardown_class') if teardown_class is not None: teardown_class = getattr(teardown_class, 'im_func', teardown_class) teardown_class = getattr(teardown_class, '__func__', teardown_class) @@ -431,7 +433,7 @@ name = 'setup_method' else: name = 'setup_function' - setup_func_or_method = getattr(obj, name, None) + setup_func_or_method = xunitsetup(obj, name) if setup_func_or_method is not None: setup_func_or_method(self.obj) @@ -442,7 +444,7 @@ else: name = 'teardown_function' obj = self.parent.obj - teardown_func_or_meth = getattr(obj, name, None) + teardown_func_or_meth = xunitsetup(obj, name) if teardown_func_or_meth is not None: teardown_func_or_meth(self.obj) @@ -1338,6 +1340,7 @@ if nodeid.startswith(setupcall.baseid): l.append(setupcall) allargnames.update(setupcall.funcargnames) + l.sort(key=lambda x: x.scopenum) return l, allargnames @@ -1479,6 +1482,7 @@ self.func = func self.funcargnames = getfuncargnames(func) self.scope = scope + self.scopenum = scopes.index(scope) self.active = False self._finalizer = [] @@ -1595,3 +1599,9 @@ # argparams.append(key) return argparams + +def xunitsetup(obj, name): + meth = getattr(obj, name, None) + if meth is not None: + if not hasattr(meth, "_pytestsetup"): + return meth diff -r 4d9f48622c63733d4d67b436d40bdb14fb1ca037 -r 57b9e4d9bdb29039856691c16a2d7b5696d0eb89 testing/test_python.py --- a/testing/test_python.py +++ b/testing/test_python.py @@ -1874,6 +1874,28 @@ l = config._conftest.getconftestmodules(p)[0].l assert l == ["fin_a1", "fin_a2", "fin_b1", "fin_b2"] * 2 + def test_setup_scope_ordering(self, testdir): + testdir.makepyfile(""" + import pytest + l = [] + @pytest.setup(scope="function") + def fappend2(): + l.append(2) + @pytest.setup(scope="class") + def classappend3(): + l.append(3) + @pytest.setup(scope="module") + def mappend(): + l.append(1) + + class TestHallo: + def test_method(self): + assert l == [1,3,2] + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) + + class TestFuncargMarker: def test_parametrize(self, testdir): testdir.makepyfile(""" @@ -2404,3 +2426,33 @@ """) reprec = testdir.inline_run() reprec.assertoutcome(passed=2) + +def test_setupdecorator_and_xunit(testdir): + testdir.makepyfile(""" + import pytest + l = [] + @pytest.setup(scope='module') + def setup_module(): + l.append("module") + @pytest.setup() + def setup_function(): + l.append("function") + + def test_func(): + pass + + class TestClass: + @pytest.setup(scope="class") + def setup_class(self): + l.append("class") + @pytest.setup() + def setup_method(self): + l.append("method") + def test_method(self): + pass + def test_all(): + assert l == ["module", "function", "class", + "function", "method", "function"] + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=3) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. _______________________________________________ py-svn mailing list py-svn@codespeak.net http://codespeak.net/mailman/listinfo/py-svn