refs #322: setUpClass and tearDownClass as autouse fixture and finalizer

This commit is contained in:
Mathieu Agopian 2013-08-01 23:48:40 +02:00
parent 3b85a56db2
commit 7fc0d45a4c
4 changed files with 94 additions and 27 deletions

View File

@ -11,6 +11,12 @@ from _pytest.main import Session, EXIT_OK
from py.builtin import print_
from _pytest.core import HookRelay
def get_public_names(l):
"""Only return names from iterator l without a leading underscore."""
return [x for x in l if x[0] != "_"]
def pytest_addoption(parser):
group = parser.getgroup("pylib")
group.addoption('--no-tools-on-path',

View File

@ -5,19 +5,38 @@ import sys, pdb
# for transfering markers
from _pytest.python import transfer_markers
def pytest_pycollect_makeitem(collector, name, obj):
def is_unittest(obj):
"""Is obj a subclass of unittest.TestCase?"""
unittest = sys.modules.get('unittest')
if unittest is None:
return # nobody can have derived unittest.TestCase
return # nobody can have derived unittest.TestCase
try:
isunit = issubclass(obj, unittest.TestCase)
return issubclass(obj, unittest.TestCase)
except KeyboardInterrupt:
raise
except Exception:
pass
else:
if isunit:
return UnitTestCase(name, parent=collector)
except:
return False
@pytest.fixture(scope='class', autouse=True)
def _xunit_setUpClass(request):
"""Add support for unittest.TestCase setUpClass and tearDownClass."""
if not is_unittest(request.cls):
return # only support setUpClass / tearDownClass for unittest.TestCase
if getattr(request.cls, '__unittest_skip__', False):
return # skipped
setup = getattr(request.cls, 'setUpClass', None)
teardown = getattr(request.cls, 'tearDownClass', None)
setup()
if teardown is not None:
request.addfinalizer(teardown)
def pytest_pycollect_makeitem(collector, name, obj):
if is_unittest(obj):
return UnitTestCase(name, parent=collector)
class UnitTestCase(pytest.Class):
nofuncargs = True # marker for fixturemanger.getfixtureinfo()
@ -45,21 +64,7 @@ class UnitTestCase(pytest.Class):
if ut is None or runtest != ut.TestCase.runTest:
yield TestCaseFunction('runTest', parent=self)
def setup(self):
if getattr(self.obj, '__unittest_skip__', False):
return
meth = getattr(self.obj, 'setUpClass', None)
if meth is not None:
meth()
super(UnitTestCase, self).setup()
def teardown(self):
if getattr(self.obj, '__unittest_skip__', False):
return
meth = getattr(self.obj, 'tearDownClass', None)
if meth is not None:
meth()
super(UnitTestCase, self).teardown()
class TestCaseFunction(pytest.Function):
_excinfo = None

View File

@ -1,6 +1,8 @@
import pytest, py, sys
from _pytest import python as funcargs
from _pytest.python import FixtureLookupError
from _pytest.pytester import get_public_names
def test_getfuncargnames():
def f(): pass
@ -50,7 +52,7 @@ class TestFillFixtures:
""")
funcargs.fillfixtures(item)
del item.funcargs["request"]
assert len(item.funcargs) == 2
assert len(get_public_names(item.funcargs)) == 2
assert item.funcargs['some'] == "test_func"
assert item.funcargs['other'] == 42
@ -334,7 +336,7 @@ class TestRequestBasic:
assert val2 == 2
pytest._fillfuncargs(item)
assert item.funcargs["something"] == 1
assert len(item.funcargs) == 2
assert len(get_public_names(item.funcargs)) == 2
assert "request" in item.funcargs
#assert item.funcargs == {'something': 1, "other": 2}
@ -412,6 +414,7 @@ class TestRequestBasic:
def test_request_fixturenames(self, testdir):
testdir.makepyfile("""
import pytest
from _pytest.pytester import get_public_names
@pytest.fixture()
def arg1():
pass
@ -422,7 +425,7 @@ class TestRequestBasic:
def sarg(tmpdir):
pass
def test_function(request, farg):
assert set(request.fixturenames) == \
assert set(get_public_names(request.fixturenames)) == \
set(["tmpdir", "sarg", "arg1", "request", "farg"])
""")
reprec = testdir.inline_run()
@ -831,6 +834,8 @@ class TestFixtureUsages:
l = reprec.getfailedcollections()
assert len(l) == 1
@pytest.mark.xfail(reason="unclear if it should be supported at all, "
"currently broken")
def test_request_can_be_overridden(self, testdir):
testdir.makepyfile("""
import pytest
@ -995,9 +1000,10 @@ class TestAutouseDiscovery:
def test_parsefactories_conftest(self, testdir):
testdir.makepyfile("""
from _pytest.pytester import get_public_names
def test_check_setup(item, fm):
autousenames = fm._getautousenames(item.nodeid)
assert len(autousenames) == 2
assert len(get_public_names(autousenames)) == 2
assert "perfunction2" in autousenames
assert "perfunction" in autousenames
""")

View File

@ -118,7 +118,7 @@ def test_teardown(testdir):
assert passed == 2
assert passed + skipped + failed == 2
@pytest.mark.skipif("sys.version_info < (3,1)")
@pytest.mark.skipif("sys.version_info < (2,7)")
def test_unittest_skip_issue148(testdir):
testpath = testdir.makepyfile("""
import unittest
@ -586,3 +586,53 @@ def test_unittest_setup_interaction(testdir):
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines("*3 passed*")
def test_non_unittest_no_setupclass_support(testdir):
testpath = testdir.makepyfile("""
class TestFoo:
x = 0
@classmethod
def setUpClass(cls):
cls.x = 1
def test_method1(self):
assert self.x == 0
@classmethod
def tearDownClass(cls):
cls.x = 1
def test_not_teareddown():
assert TestFoo.x == 0
""")
reprec = testdir.inline_run(testpath)
reprec.assertoutcome(passed=2)
def test_no_teardown_if_setupclass_failed(testdir):
testpath = testdir.makepyfile("""
import unittest
class MyTestCase(unittest.TestCase):
x = 0
@classmethod
def setUpClass(cls):
cls.x = 1
assert False
def test_func1(self):
cls.x = 10
@classmethod
def tearDownClass(cls):
cls.x = 100
def test_notTornDown():
assert MyTestCase.x == 1
""")
reprec = testdir.inline_run(testpath)
reprec.assertoutcome(passed=1, failed=1)