fix #59: provide better Jenkins stdout and stderr sections
This commit is contained in:
parent
aafe6a8e34
commit
f3bc197afb
|
@ -1,6 +1,7 @@
|
||||||
Changes between 2.1.0 and 2.1.1.DEV
|
Changes between 2.1.0 and 2.1.1.DEV
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
- fix issue59: provide system-out/err tags for junitxml output
|
||||||
- fix assertion rewriting on boolean operations with 3 or more operands
|
- fix assertion rewriting on boolean operations with 3 or more operands
|
||||||
|
|
||||||
Changes between 2.0.3 and 2.1.0.DEV
|
Changes between 2.0.3 and 2.1.0.DEV
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#
|
#
|
||||||
__version__ = '2.1.1.dev1'
|
__version__ = '2.1.1.dev2'
|
||||||
|
|
|
@ -12,12 +12,9 @@ def pytest_addoption(parser):
|
||||||
help="shortcut for --capture=no.")
|
help="shortcut for --capture=no.")
|
||||||
|
|
||||||
def addouterr(rep, outerr):
|
def addouterr(rep, outerr):
|
||||||
repr = getattr(rep, 'longrepr', None)
|
|
||||||
if not hasattr(repr, 'addsection'):
|
|
||||||
return
|
|
||||||
for secname, content in zip(["out", "err"], outerr):
|
for secname, content in zip(["out", "err"], outerr):
|
||||||
if content:
|
if content:
|
||||||
repr.addsection("Captured std%s" % secname, content.rstrip())
|
rep.sections.append(("Captured std%s" % secname, content))
|
||||||
|
|
||||||
def pytest_unconfigure(config):
|
def pytest_unconfigure(config):
|
||||||
# registered in config.py during early conftest.py loading
|
# registered in config.py during early conftest.py loading
|
||||||
|
|
|
@ -114,8 +114,16 @@ class LogXML(object):
|
||||||
'<skipped message="xfail-marked test passes unexpectedly"/>')
|
'<skipped message="xfail-marked test passes unexpectedly"/>')
|
||||||
self.skipped += 1
|
self.skipped += 1
|
||||||
else:
|
else:
|
||||||
self.appendlog('<failure message="test failure">%s</failure>',
|
sec = dict(report.sections)
|
||||||
report.longrepr)
|
fmt = '<failure message="test failure">%s'
|
||||||
|
args = [report.longrepr]
|
||||||
|
for name in ('out', 'err'):
|
||||||
|
content = sec.get("Captured std%s" % name)
|
||||||
|
if content:
|
||||||
|
fmt += "<system-%s>%%s</system-%s>" % (name, name)
|
||||||
|
args.append(content)
|
||||||
|
fmt += "</failure>"
|
||||||
|
self.appendlog(fmt, *args)
|
||||||
self.failed += 1
|
self.failed += 1
|
||||||
self._closetestcase()
|
self._closetestcase()
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ class TestReport(BaseReport):
|
||||||
they fail).
|
they fail).
|
||||||
"""
|
"""
|
||||||
def __init__(self, nodeid, location,
|
def __init__(self, nodeid, location,
|
||||||
keywords, outcome, longrepr, when):
|
keywords, outcome, longrepr, when, sections=()):
|
||||||
#: normalized collection node id
|
#: normalized collection node id
|
||||||
self.nodeid = nodeid
|
self.nodeid = nodeid
|
||||||
|
|
||||||
|
@ -189,6 +189,10 @@ class TestReport(BaseReport):
|
||||||
#: one of 'setup', 'call', 'teardown' to indicate runtest phase.
|
#: one of 'setup', 'call', 'teardown' to indicate runtest phase.
|
||||||
self.when = when
|
self.when = when
|
||||||
|
|
||||||
|
#: list of (secname, data) extra information which needs to
|
||||||
|
#: marshallable
|
||||||
|
self.sections = list(sections)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<TestReport %r when=%r outcome=%r>" % (
|
return "<TestReport %r when=%r outcome=%r>" % (
|
||||||
self.nodeid, self.when, self.outcome)
|
self.nodeid, self.when, self.outcome)
|
||||||
|
@ -198,6 +202,7 @@ class TeardownErrorReport(BaseReport):
|
||||||
when = "teardown"
|
when = "teardown"
|
||||||
def __init__(self, longrepr):
|
def __init__(self, longrepr):
|
||||||
self.longrepr = longrepr
|
self.longrepr = longrepr
|
||||||
|
self.sections = []
|
||||||
|
|
||||||
def pytest_make_collect_report(collector):
|
def pytest_make_collect_report(collector):
|
||||||
call = CallInfo(collector._memocollect, "memocollect")
|
call = CallInfo(collector._memocollect, "memocollect")
|
||||||
|
@ -219,11 +224,12 @@ def pytest_make_collect_report(collector):
|
||||||
getattr(call, 'result', None))
|
getattr(call, 'result', None))
|
||||||
|
|
||||||
class CollectReport(BaseReport):
|
class CollectReport(BaseReport):
|
||||||
def __init__(self, nodeid, outcome, longrepr, result):
|
def __init__(self, nodeid, outcome, longrepr, result, sections=()):
|
||||||
self.nodeid = nodeid
|
self.nodeid = nodeid
|
||||||
self.outcome = outcome
|
self.outcome = outcome
|
||||||
self.longrepr = longrepr
|
self.longrepr = longrepr
|
||||||
self.result = result or []
|
self.result = result or []
|
||||||
|
self.sections = list(sections)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def location(self):
|
def location(self):
|
||||||
|
|
|
@ -393,7 +393,7 @@ class TerminalReporter:
|
||||||
else:
|
else:
|
||||||
msg = self._getfailureheadline(rep)
|
msg = self._getfailureheadline(rep)
|
||||||
self.write_sep("_", msg)
|
self.write_sep("_", msg)
|
||||||
rep.toterminal(self._tw)
|
self._outrep_summary(rep)
|
||||||
|
|
||||||
def summary_errors(self):
|
def summary_errors(self):
|
||||||
if self.config.option.tbstyle != "no":
|
if self.config.option.tbstyle != "no":
|
||||||
|
@ -411,7 +411,15 @@ class TerminalReporter:
|
||||||
elif rep.when == "teardown":
|
elif rep.when == "teardown":
|
||||||
msg = "ERROR at teardown of " + msg
|
msg = "ERROR at teardown of " + msg
|
||||||
self.write_sep("_", msg)
|
self.write_sep("_", msg)
|
||||||
rep.toterminal(self._tw)
|
self._outrep_summary(rep)
|
||||||
|
|
||||||
|
def _outrep_summary(self, rep):
|
||||||
|
rep.toterminal(self._tw)
|
||||||
|
for secname, content in rep.sections:
|
||||||
|
self._tw.sep("-", secname)
|
||||||
|
if content[-1:] == "\n":
|
||||||
|
content = content[:-1]
|
||||||
|
self._tw.line(content)
|
||||||
|
|
||||||
def summary_stats(self):
|
def summary_stats(self):
|
||||||
session_duration = py.std.time.time() - self._sessionstarttime
|
session_duration = py.std.time.time() - self._sessionstarttime
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -24,7 +24,7 @@ def main():
|
||||||
name='pytest',
|
name='pytest',
|
||||||
description='py.test: simple powerful testing with Python',
|
description='py.test: simple powerful testing with Python',
|
||||||
long_description = long_description,
|
long_description = long_description,
|
||||||
version='2.1.1.dev1',
|
version='2.1.1.dev2',
|
||||||
url='http://pytest.org',
|
url='http://pytest.org',
|
||||||
license='MIT license',
|
license='MIT license',
|
||||||
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
|
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
|
||||||
|
@ -32,7 +32,7 @@ def main():
|
||||||
author_email='holger at merlinux.eu',
|
author_email='holger at merlinux.eu',
|
||||||
entry_points= make_entry_points(),
|
entry_points= make_entry_points(),
|
||||||
# the following should be enabled for release
|
# the following should be enabled for release
|
||||||
install_requires=['py>=1.4.4'],
|
install_requires=['py>=1.4.5.dev1'],
|
||||||
classifiers=['Development Status :: 5 - Production/Stable',
|
classifiers=['Development Status :: 5 - Production/Stable',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: MIT License',
|
'License :: OSI Approved :: MIT License',
|
||||||
|
|
|
@ -131,7 +131,14 @@ class TestPython:
|
||||||
assert "Division" in fnode.toxml()
|
assert "Division" in fnode.toxml()
|
||||||
|
|
||||||
def test_failure_function(self, testdir):
|
def test_failure_function(self, testdir):
|
||||||
testdir.makepyfile("def test_fail(): raise ValueError(42)")
|
testdir.makepyfile("""
|
||||||
|
import sys
|
||||||
|
def test_fail():
|
||||||
|
print ("hello-stdout")
|
||||||
|
sys.stderr.write("hello-stderr\\n")
|
||||||
|
raise ValueError(42)
|
||||||
|
""")
|
||||||
|
|
||||||
result, dom = runandparse(testdir)
|
result, dom = runandparse(testdir)
|
||||||
assert result.ret
|
assert result.ret
|
||||||
node = dom.getElementsByTagName("testsuite")[0]
|
node = dom.getElementsByTagName("testsuite")[0]
|
||||||
|
@ -143,6 +150,10 @@ class TestPython:
|
||||||
fnode = tnode.getElementsByTagName("failure")[0]
|
fnode = tnode.getElementsByTagName("failure")[0]
|
||||||
assert_attr(fnode, message="test failure")
|
assert_attr(fnode, message="test failure")
|
||||||
assert "ValueError" in fnode.toxml()
|
assert "ValueError" in fnode.toxml()
|
||||||
|
systemout = fnode.getElementsByTagName("system-out")[0]
|
||||||
|
assert "hello-stdout" in systemout.toxml()
|
||||||
|
systemerr = fnode.getElementsByTagName("system-err")[0]
|
||||||
|
assert "hello-stderr" in systemerr.toxml()
|
||||||
|
|
||||||
def test_failure_escape(self, testdir):
|
def test_failure_escape(self, testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
|
|
|
@ -258,10 +258,13 @@ class TestCollectonly:
|
||||||
|
|
||||||
|
|
||||||
def test_repr_python_version(monkeypatch):
|
def test_repr_python_version(monkeypatch):
|
||||||
monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0))
|
try:
|
||||||
assert repr_pythonversion() == "2.5.1-final-0"
|
monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0))
|
||||||
py.std.sys.version_info = x = (2,3)
|
assert repr_pythonversion() == "2.5.1-final-0"
|
||||||
assert repr_pythonversion() == str(x)
|
py.std.sys.version_info = x = (2,3)
|
||||||
|
assert repr_pythonversion() == str(x)
|
||||||
|
finally:
|
||||||
|
monkeypatch.undo() # do this early as pytest can get confused
|
||||||
|
|
||||||
class TestFixtureReporting:
|
class TestFixtureReporting:
|
||||||
def test_setup_fixture_error(self, testdir):
|
def test_setup_fixture_error(self, testdir):
|
||||||
|
|
Loading…
Reference in New Issue