From dba2a8bc647c73eb9ecf21de18bf56e45a04f115 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 6 Nov 2012 11:04:11 +0100 Subject: [PATCH] fix issue217 - to support @mock.patch with pytest funcarg-fixtures, also split out python integration tests into python/integration.py and fix nose/mark tests --- CHANGELOG | 3 + _pytest/__init__.py | 2 +- _pytest/python.py | 6 ++ setup.py | 2 +- testing/python/fixture.py | 53 --------------- testing/python/integration.py | 119 ++++++++++++++++++++++++++++++++++ testing/test_mark.py | 2 +- testing/test_nose.py | 14 +--- tox.ini | 2 + 9 files changed, 136 insertions(+), 67 deletions(-) create mode 100644 testing/python/integration.py diff --git a/CHANGELOG b/CHANGELOG index 1dd4bae37..67f7d3421 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,9 @@ Changes between 2.3.2 and 2.3.3.dev - in tracebacks *,** arg values are now shown next to normal arguments (thanks Manuel Jacob) +- fix issue217 - support mock.patch with pytest's fixtures - note that + you need either mock-1.0.1 or the python3.3 builtin unittest.mock. + Changes between 2.3.1 and 2.3.2 ----------------------------------- diff --git a/_pytest/__init__.py b/_pytest/__init__.py index d17a859f7..cdd940d10 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.3.3.dev3' +__version__ = '2.3.3.dev4' diff --git a/_pytest/python.py b/_pytest/python.py index 5b35ab272..9af008611 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1659,8 +1659,14 @@ class FixtureDef: def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames #assert not inspect.isclass(function) + realfunction = function + while hasattr(realfunction, "__wrapped__"): + realfunction = realfunction.__wrapped__ if startindex is None: startindex = inspect.ismethod(function) and 1 or 0 + if realfunction != function: + startindex += len(getattr(function, "patchings", [])) + function = realfunction argnames = inspect.getargs(py.code.getrawcode(function))[0] defaults = getattr(function, 'func_defaults', getattr(function, '__defaults__', None)) or () diff --git a/setup.py b/setup.py index 8082f93d0..719681fd8 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.3.3.dev3', + version='2.3.3.dev4', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 04bdc6374..a5637fbff 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -541,59 +541,6 @@ class TestRequestCachedSetup: "*ZeroDivisionError*", ]) -class TestOEJSKITSpecials: - def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage - testdir.makeconftest(""" - import pytest - def pytest_pycollect_makeitem(collector, name, obj): - if name == "MyClass": - return MyCollector(name, parent=collector) - class MyCollector(pytest.Collector): - def reportinfo(self): - return self.fspath, 3, "xyz" - """) - modcol = testdir.getmodulecol(""" - def pytest_funcarg__arg1(request): - return 42 - class MyClass: - pass - """) - # this hook finds funcarg factories - rep = modcol.ihook.pytest_make_collect_report(collector=modcol) - clscol = rep.result[0] - clscol.obj = lambda arg1: None - clscol.funcargs = {} - funcargs.fillfixtures(clscol) - assert clscol.funcargs['arg1'] == 42 - - def test_autouse_fixture(self, testdir): # rough jstests usage - testdir.makeconftest(""" - import pytest - def pytest_pycollect_makeitem(collector, name, obj): - if name == "MyClass": - return MyCollector(name, parent=collector) - class MyCollector(pytest.Collector): - def reportinfo(self): - return self.fspath, 3, "xyz" - """) - modcol = testdir.getmodulecol(""" - import pytest - @pytest.fixture(autouse=True) - def hello(): - pass - def pytest_funcarg__arg1(request): - return 42 - class MyClass: - pass - """) - # this hook finds funcarg factories - rep = modcol.ihook.pytest_make_collect_report(collector=modcol) - clscol = rep.result[0] - clscol.obj = lambda: None - clscol.funcargs = {} - funcargs.fillfixtures(clscol) - assert not clscol.funcargs - class TestFixtureUsages: def test_noargfixturedec(self, testdir): testdir.makepyfile(""" diff --git a/testing/python/integration.py b/testing/python/integration.py new file mode 100644 index 000000000..a191254c6 --- /dev/null +++ b/testing/python/integration.py @@ -0,0 +1,119 @@ +import pytest, py, sys + +class TestOEJSKITSpecials: + def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage + testdir.makeconftest(""" + import pytest + def pytest_pycollect_makeitem(collector, name, obj): + if name == "MyClass": + return MyCollector(name, parent=collector) + class MyCollector(pytest.Collector): + def reportinfo(self): + return self.fspath, 3, "xyz" + """) + modcol = testdir.getmodulecol(""" + def pytest_funcarg__arg1(request): + return 42 + class MyClass: + pass + """) + # this hook finds funcarg factories + rep = modcol.ihook.pytest_make_collect_report(collector=modcol) + clscol = rep.result[0] + clscol.obj = lambda arg1: None + clscol.funcargs = {} + pytest._fillfuncargs(clscol) + assert clscol.funcargs['arg1'] == 42 + + def test_autouse_fixture(self, testdir): # rough jstests usage + testdir.makeconftest(""" + import pytest + def pytest_pycollect_makeitem(collector, name, obj): + if name == "MyClass": + return MyCollector(name, parent=collector) + class MyCollector(pytest.Collector): + def reportinfo(self): + return self.fspath, 3, "xyz" + """) + modcol = testdir.getmodulecol(""" + import pytest + @pytest.fixture(autouse=True) + def hello(): + pass + def pytest_funcarg__arg1(request): + return 42 + class MyClass: + pass + """) + # this hook finds funcarg factories + rep = modcol.ihook.pytest_make_collect_report(collector=modcol) + clscol = rep.result[0] + clscol.obj = lambda: None + clscol.funcargs = {} + pytest._fillfuncargs(clscol) + assert not clscol.funcargs + + +class TestMockDecoration: + def test_wrapped_getfuncargnames(self): + from _pytest.python import getfuncargnames + def wrap(f): + def func(): + pass + func.__wrapped__ = f + return func + @wrap + def f(x): + pass + l = getfuncargnames(f) + assert l == ("x",) + + def test_wrapped_getfuncargnames_patching(self): + from _pytest.python import getfuncargnames + def wrap(f): + def func(): + pass + func.__wrapped__ = f + func.patchings = ["qwe"] + return func + @wrap + def f(x, y, z): + pass + l = getfuncargnames(f) + assert l == ("y", "z") + + def test_unittest_mock(self, testdir): + pytest.importorskip("unittest.mock") + testdir.makepyfile(""" + import unittest.mock + class T(unittest.TestCase): + @unittest.mock.patch("os.path.abspath") + def test_hello(self, abspath): + import os + os.path.abspath("hello") + abspath.assert_any_call("hello") + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) + + def test_mock(self, testdir): + pytest.importorskip("mock", "1.0.1") + testdir.makepyfile(""" + import os + import unittest + import mock + + class T(unittest.TestCase): + @mock.patch("os.path.abspath") + def test_hello(self, abspath): + os.path.abspath("hello") + abspath.assert_any_call("hello") + @mock.patch("os.path.abspath") + @mock.patch("os.path.normpath") + def test_someting(normpath, abspath, tmpdir): + abspath.return_value = "this" + os.path.normpath(os.path.abspath("hello")) + normpath.assert_any_call("this") + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=2) diff --git a/testing/test_mark.py b/testing/test_mark.py index 73055d13d..4fc3199ad 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -253,7 +253,7 @@ class TestFunctional: """) items, rec = testdir.inline_genitems(p) for item in items: - print item, item.keywords + print (item, item.keywords) assert 'a' in item.keywords def test_mark_with_wrong_marker(self, testdir): diff --git a/testing/test_nose.py b/testing/test_nose.py index 1d80e241b..99d10f9c3 100644 --- a/testing/test_nose.py +++ b/testing/test_nose.py @@ -103,21 +103,13 @@ def test_nose_setup_func_failure_2(testdir): my_teardown = 2 def test_hello(): - print (l) - assert l == [1] - - def test_world(): - print (l) - assert l == [1,2] + assert l == [] test_hello.setup = my_setup test_hello.teardown = my_teardown """) - result = testdir.runpytest(p, '-p', 'nose') - result.stdout.fnmatch_lines([ - "*TypeError: 'int' object is not callable*" - ]) - + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) def test_nose_setup_partial(testdir): py.test.importorskip("functools") diff --git a/tox.ini b/tox.ini index b3196fd1e..6928fa4f9 100644 --- a/tox.ini +++ b/tox.ini @@ -21,6 +21,8 @@ commands= py.test --genscript=pytest1 changedir=. basepython=python2.7 deps=pytest-xdist + :pypi:mock + :pypi:nose commands= py.test -n3 -rfsxX \ --junitxml={envlogdir}/junit-{envname}.xml testing