[svn r63628] * shuffle SetupState and fixture handling into runner.py
* introduce a itemsetupreport and new setupitem/teardownitem methods. * more tests --HG-- branch : trunk
This commit is contained in:
parent
ec2c167264
commit
ba6eca8da4
|
@ -3,6 +3,7 @@ from conftesthandle import Conftest
|
||||||
|
|
||||||
from py.__.test import parseopt
|
from py.__.test import parseopt
|
||||||
from py.__.misc.warn import APIWARN
|
from py.__.misc.warn import APIWARN
|
||||||
|
from py.__.test.runner import SetupState
|
||||||
|
|
||||||
def ensuretemp(string, dir=1):
|
def ensuretemp(string, dir=1):
|
||||||
""" return temporary directory path with
|
""" return temporary directory path with
|
||||||
|
@ -312,34 +313,6 @@ def gettopdir(args):
|
||||||
else:
|
else:
|
||||||
return pkgdir.dirpath()
|
return pkgdir.dirpath()
|
||||||
|
|
||||||
class SetupState(object):
|
|
||||||
""" shared state for setting up/tearing down test items or collectors. """
|
|
||||||
def __init__(self):
|
|
||||||
self.stack = []
|
|
||||||
|
|
||||||
def teardown_all(self):
|
|
||||||
while self.stack:
|
|
||||||
col = self.stack.pop()
|
|
||||||
col.teardown()
|
|
||||||
|
|
||||||
def teardown_exact(self, item):
|
|
||||||
if self.stack and self.stack[-1] == item:
|
|
||||||
col = self.stack.pop()
|
|
||||||
col.teardown()
|
|
||||||
|
|
||||||
def prepare(self, colitem):
|
|
||||||
""" setup objects along the collector chain to the test-method
|
|
||||||
Teardown any unneccessary previously setup objects."""
|
|
||||||
|
|
||||||
needed_collectors = colitem.listchain()
|
|
||||||
while self.stack:
|
|
||||||
if self.stack == needed_collectors[:len(self.stack)]:
|
|
||||||
break
|
|
||||||
col = self.stack.pop()
|
|
||||||
col.teardown()
|
|
||||||
for col in needed_collectors[len(self.stack):]:
|
|
||||||
col.setup()
|
|
||||||
self.stack.append(col)
|
|
||||||
|
|
||||||
# this is the one per-process instance of py.test configuration
|
# this is the one per-process instance of py.test configuration
|
||||||
config_per_process = Config(
|
config_per_process = Config(
|
||||||
|
|
|
@ -85,6 +85,9 @@ class Events:
|
||||||
def pyevent__itemtestreport(self, event):
|
def pyevent__itemtestreport(self, event):
|
||||||
""" test has been run. """
|
""" test has been run. """
|
||||||
|
|
||||||
|
def pyevent__itemsetupreport(self, rep):
|
||||||
|
""" test has been run. """
|
||||||
|
|
||||||
def pyevent__deselected(self, items):
|
def pyevent__deselected(self, items):
|
||||||
""" collected items that were deselected (by keyword). """
|
""" collected items that were deselected (by keyword). """
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,11 @@ class TmpTestdir:
|
||||||
if hasattr(self, '_olddir'):
|
if hasattr(self, '_olddir'):
|
||||||
self._olddir.chdir()
|
self._olddir.chdir()
|
||||||
|
|
||||||
|
def geteventrecorder(self, config):
|
||||||
|
evrec = EventRecorder(config.bus)
|
||||||
|
self.pyfuncitem.addfinalizer(lambda: config.bus.unregister(evrec))
|
||||||
|
return evrec
|
||||||
|
|
||||||
def chdir(self):
|
def chdir(self):
|
||||||
old = self.tmpdir.chdir()
|
old = self.tmpdir.chdir()
|
||||||
if not hasattr(self, '_olddir'):
|
if not hasattr(self, '_olddir'):
|
||||||
|
@ -174,9 +179,12 @@ class TmpTestdir:
|
||||||
|
|
||||||
def getitem(self, source, funcname="test_func"):
|
def getitem(self, source, funcname="test_func"):
|
||||||
modcol = self.getmodulecol(source)
|
modcol = self.getmodulecol(source)
|
||||||
item = modcol.join(funcname)
|
moditems = modcol.collect()
|
||||||
assert item is not None, "%r item not found in module:\n%s" %(funcname, source)
|
for item in modcol.collect():
|
||||||
|
if item.name == funcname:
|
||||||
return item
|
return item
|
||||||
|
else:
|
||||||
|
assert 0, "%r item not found in module:\n%s" %(funcname, source)
|
||||||
|
|
||||||
def getitems(self, source):
|
def getitems(self, source):
|
||||||
modcol = self.getmodulecol(source)
|
modcol = self.getmodulecol(source)
|
||||||
|
@ -284,12 +292,13 @@ class EventRecorder(object):
|
||||||
for i, event in py.builtin.enumerate(self.events):
|
for i, event in py.builtin.enumerate(self.events):
|
||||||
if event.name == name:
|
if event.name == name:
|
||||||
del self.events[i]
|
del self.events[i]
|
||||||
return event
|
eventparser = self.geteventparser(name)
|
||||||
|
return eventparser(*event.args, **event.kwargs)
|
||||||
raise KeyError("popevent: %r not found in %r" %(name, self.events))
|
raise KeyError("popevent: %r not found in %r" %(name, self.events))
|
||||||
|
|
||||||
def getevents(self, eventname):
|
def getevents(self, eventname):
|
||||||
""" return list of ParsedEvent instances matching the given eventname. """
|
""" return list of ParsedEvent instances matching the given eventname. """
|
||||||
method = self.geteventmethod(eventname)
|
method = self.geteventparser(eventname)
|
||||||
l = []
|
l = []
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
if event.name == eventname:
|
if event.name == eventname:
|
||||||
|
@ -297,23 +306,18 @@ class EventRecorder(object):
|
||||||
l.append(pevent)
|
l.append(pevent)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
def geteventmethod(self, eventname):
|
def geteventparser(self, eventname):
|
||||||
mname = "pyevent__" + eventname
|
mname = "pyevent__" + eventname
|
||||||
method = getattr(api.Events, mname)
|
method = getattr(api.Events, mname)
|
||||||
args, varargs, varkw, default = inspect.getargspec(method)
|
args, varargs, varkw, default = inspect.getargspec(method)
|
||||||
assert args[0] == "self"
|
assert args[0] == "self"
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
fspec = inspect.formatargspec(args, varargs, varkw, default)
|
fspec = inspect.formatargspec(args, varargs, varkw, default)
|
||||||
source = """def %(mname)s%(fspec)s:
|
code = py.code.compile("""def %(mname)s%(fspec)s:
|
||||||
return ParsedEvent(locals())""" % locals()
|
return ParsedEvent(locals())""" % locals())
|
||||||
print source
|
exec code
|
||||||
exec source
|
|
||||||
return locals()[mname]
|
return locals()[mname]
|
||||||
|
|
||||||
|
|
||||||
def firstparsedevent(self, eventname):
|
|
||||||
return self.parsedevents(eventname)[0]
|
|
||||||
|
|
||||||
def get(self, cls):
|
def get(self, cls):
|
||||||
l = []
|
l = []
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* and generating report events about it
|
* and generating report events about it
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import py, os, sys
|
import py
|
||||||
|
|
||||||
from py.__.test.outcome import Exit, Skipped
|
from py.__.test.outcome import Exit, Skipped
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@ def basic_collect_report(collector):
|
||||||
return CollectionReport(collector, res, excinfo, outerr)
|
return CollectionReport(collector, res, excinfo, outerr)
|
||||||
|
|
||||||
from cPickle import Pickler, Unpickler
|
from cPickle import Pickler, Unpickler
|
||||||
from cStringIO import StringIO
|
|
||||||
|
|
||||||
def forked_run_report(item, pdb=None):
|
def forked_run_report(item, pdb=None):
|
||||||
EXITSTATUS_TESTEXIT = 4
|
EXITSTATUS_TESTEXIT = 4
|
||||||
|
@ -66,7 +65,7 @@ def forked_run_report(item, pdb=None):
|
||||||
try:
|
try:
|
||||||
testrep = basic_run_report(item)
|
testrep = basic_run_report(item)
|
||||||
except (KeyboardInterrupt, Exit):
|
except (KeyboardInterrupt, Exit):
|
||||||
os._exit(EXITSTATUS_TESTEXIT)
|
py.std.os._exit(EXITSTATUS_TESTEXIT)
|
||||||
return ipickle.dumps(testrep)
|
return ipickle.dumps(testrep)
|
||||||
|
|
||||||
ff = py.process.ForkedFunc(runforked)
|
ff = py.process.ForkedFunc(runforked)
|
||||||
|
@ -164,3 +163,70 @@ class CollectionReport(BaseReport):
|
||||||
else:
|
else:
|
||||||
out.line(str(longrepr))
|
out.line(str(longrepr))
|
||||||
|
|
||||||
|
class ItemSetupReport(BaseReport):
|
||||||
|
""" Test Execution Report. """
|
||||||
|
failed = passed = skipped = False
|
||||||
|
|
||||||
|
def __init__(self, item, excinfo=None, outerr=None):
|
||||||
|
self.item = item
|
||||||
|
self.outerr = outerr
|
||||||
|
if not excinfo:
|
||||||
|
self.passed = True
|
||||||
|
else:
|
||||||
|
if excinfo.errisinstance(Skipped):
|
||||||
|
self.skipped = True
|
||||||
|
else:
|
||||||
|
self.failed = True
|
||||||
|
self.excrepr = item._repr_failure_py(excinfo, outerr)
|
||||||
|
|
||||||
|
class SetupState(object):
|
||||||
|
""" shared state for setting up/tearing down test items or collectors. """
|
||||||
|
def __init__(self):
|
||||||
|
self.stack = []
|
||||||
|
|
||||||
|
def teardown_all(self):
|
||||||
|
while self.stack:
|
||||||
|
col = self.stack.pop()
|
||||||
|
col.teardown()
|
||||||
|
|
||||||
|
def teardown_exact(self, item):
|
||||||
|
if self.stack and self.stack[-1] == item:
|
||||||
|
col = self.stack.pop()
|
||||||
|
col.teardown()
|
||||||
|
|
||||||
|
def prepare(self, colitem):
|
||||||
|
""" setup objects along the collector chain to the test-method
|
||||||
|
Teardown any unneccessary previously setup objects."""
|
||||||
|
needed_collectors = colitem.listchain()
|
||||||
|
while self.stack:
|
||||||
|
if self.stack == needed_collectors[:len(self.stack)]:
|
||||||
|
break
|
||||||
|
col = self.stack.pop()
|
||||||
|
col.teardown()
|
||||||
|
for col in needed_collectors[len(self.stack):]:
|
||||||
|
col.setup()
|
||||||
|
self.stack.append(col)
|
||||||
|
|
||||||
|
def fixturecall(self, callable, item):
|
||||||
|
excinfo = None
|
||||||
|
capture = item.config._getcapture()
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
callable(item)
|
||||||
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
excinfo = py.code.ExceptionInfo()
|
||||||
|
finally:
|
||||||
|
outerr = capture.reset()
|
||||||
|
if not excinfo:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
rep = ItemSetupReport(item, excinfo, outerr)
|
||||||
|
item.config.pytestplugins.notify("itemsetupreport", rep)
|
||||||
|
|
||||||
|
def setupitem(self, item):
|
||||||
|
return self.fixturecall(self.prepare, item)
|
||||||
|
|
||||||
|
def teardownitem(self, item):
|
||||||
|
self.fixturecall(self.teardown_exact, item)
|
||||||
|
|
|
@ -138,3 +138,74 @@ def test_method_setup_uses_fresh_instances(testdir):
|
||||||
assert not hasattr(self, 'world')
|
assert not hasattr(self, 'world')
|
||||||
""")
|
""")
|
||||||
sorter.assertoutcome(passed=4, failed=0)
|
sorter.assertoutcome(passed=4, failed=0)
|
||||||
|
|
||||||
|
from py.__.test.config import SetupState
|
||||||
|
|
||||||
|
class TestSetupState:
|
||||||
|
def test_setupitem_works(self, testdir):
|
||||||
|
item = testdir.getitem("""
|
||||||
|
def setup_module(mod):
|
||||||
|
pass
|
||||||
|
def test_func():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
evrec = testdir.geteventrecorder(item.config)
|
||||||
|
setup = SetupState()
|
||||||
|
res = setup.setupitem(item)
|
||||||
|
assert res
|
||||||
|
|
||||||
|
def test_setupitem_fails(self, testdir):
|
||||||
|
item = testdir.getitem("""
|
||||||
|
def setup_module(mod):
|
||||||
|
print "world"
|
||||||
|
raise ValueError(42)
|
||||||
|
def test_func():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
evrec = testdir.geteventrecorder(item.config)
|
||||||
|
setup = SetupState()
|
||||||
|
res = setup.setupitem(item)
|
||||||
|
assert not res
|
||||||
|
rep = evrec.popevent("itemsetupreport").rep
|
||||||
|
assert rep.failed
|
||||||
|
assert not rep.skipped
|
||||||
|
assert rep.excrepr
|
||||||
|
assert "42" in str(rep.excrepr)
|
||||||
|
assert rep.outerr[0].find("world") != -1
|
||||||
|
|
||||||
|
def test_teardownitem_fails(self, testdir):
|
||||||
|
item = testdir.getitem("""
|
||||||
|
def test_func():
|
||||||
|
pass
|
||||||
|
def teardown_function(func):
|
||||||
|
print "13"
|
||||||
|
raise ValueError(25)
|
||||||
|
""")
|
||||||
|
evrec = testdir.geteventrecorder(item.config)
|
||||||
|
setup = SetupState()
|
||||||
|
res = setup.setupitem(item)
|
||||||
|
assert res
|
||||||
|
setup.teardownitem(item)
|
||||||
|
rep = evrec.popevent("itemsetupreport").rep
|
||||||
|
assert rep.item == item
|
||||||
|
assert rep.failed
|
||||||
|
assert not rep.passed
|
||||||
|
assert "13" in rep.outerr[0]
|
||||||
|
assert "25" in str(rep.excrepr)
|
||||||
|
|
||||||
|
def test_setupitem_skips(self, testdir):
|
||||||
|
item = testdir.getitem("""
|
||||||
|
import py
|
||||||
|
def setup_module(mod):
|
||||||
|
py.test.skip("17")
|
||||||
|
def test_func():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
evrec = testdir.geteventrecorder(item.config)
|
||||||
|
setup = SetupState()
|
||||||
|
setup.setupitem(item)
|
||||||
|
rep = evrec.popevent("itemsetupreport").rep
|
||||||
|
assert not rep.failed
|
||||||
|
assert rep.skipped
|
||||||
|
assert rep.excrepr
|
||||||
|
assert "17" in str(rep.excrepr)
|
Loading…
Reference in New Issue