Merge pull request #809 from kevincox/junitxml-file-attribute

Add `file` and `line` attributes to junit-xml output.
This commit is contained in:
Bruno Oliveira 2015-07-03 08:24:36 -03:00
commit 9293062221
4 changed files with 39 additions and 5 deletions

View File

@ -39,6 +39,7 @@ Janne Vanhala
Jason R. Coombs Jason R. Coombs
Jurko Gospodnetić Jurko Gospodnetić
Katarzyna Jachim Katarzyna Jachim
Kevin Cox
Maciek Fijalkowski Maciek Fijalkowski
Maho Maho
Marc Schlaich Marc Schlaich

View File

@ -67,6 +67,8 @@
- add a new ``--noconftest`` argument which ignores all ``conftest.py`` files. - add a new ``--noconftest`` argument which ignores all ``conftest.py`` files.
- add ``file`` and ``line`` attributes to JUnit-XML output.
2.7.2 (compared to 2.7.1) 2.7.2 (compared to 2.7.1)
----------------------------- -----------------------------

View File

@ -1,5 +1,7 @@
""" report test results in JUnit-XML format, for use with Hudson and build integration servers. """ report test results in JUnit-XML format, for use with Hudson and build integration servers.
Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
Based on initial code from Ross Lawley. Based on initial code from Ross Lawley.
""" """
import py import py
@ -93,11 +95,15 @@ class LogXML(object):
classnames = names[:-1] classnames = names[:-1]
if self.prefix: if self.prefix:
classnames.insert(0, self.prefix) classnames.insert(0, self.prefix)
self.tests.append(Junit.testcase( attrs = {
classname=".".join(classnames), "classname": ".".join(classnames),
name=bin_xml_escape(names[-1]), "name": bin_xml_escape(names[-1]),
time=0 "file": report.location[0],
)) "time": 0,
}
if report.location[1] is not None:
attrs["line"] = report.location[1]
self.tests.append(Junit.testcase(**attrs))
def _write_captured_output(self, report): def _write_captured_output(self, report):
for capname in ('out', 'err'): for capname in ('out', 'err'):

View File

@ -70,6 +70,8 @@ class TestPython:
assert_attr(node, errors=1, tests=0) assert_attr(node, errors=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_setup_error.py",
line="2",
classname="test_setup_error", classname="test_setup_error",
name="test_function") name="test_function")
fnode = tnode.getElementsByTagName("error")[0] fnode = tnode.getElementsByTagName("error")[0]
@ -88,6 +90,8 @@ class TestPython:
assert_attr(node, skips=1) assert_attr(node, skips=1)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_skip_contains_name_reason.py",
line="1",
classname="test_skip_contains_name_reason", classname="test_skip_contains_name_reason",
name="test_skip") name="test_skip")
snode = tnode.getElementsByTagName("skipped")[0] snode = tnode.getElementsByTagName("skipped")[0]
@ -108,6 +112,8 @@ class TestPython:
assert_attr(node, failures=1) assert_attr(node, failures=1)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_classname_instance.py",
line="1",
classname="test_classname_instance.TestClass", classname="test_classname_instance.TestClass",
name="test_method") name="test_method")
@ -120,6 +126,8 @@ class TestPython:
assert_attr(node, failures=1) assert_attr(node, failures=1)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file=os.path.join("sub", "test_hello.py"),
line="0",
classname="sub.test_hello", classname="sub.test_hello",
name="test_func") name="test_func")
@ -151,6 +159,8 @@ class TestPython:
assert_attr(node, failures=1, tests=1) assert_attr(node, failures=1, tests=1)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_failure_function.py",
line="1",
classname="test_failure_function", classname="test_failure_function",
name="test_fail") name="test_fail")
fnode = tnode.getElementsByTagName("failure")[0] fnode = tnode.getElementsByTagName("failure")[0]
@ -193,6 +203,8 @@ class TestPython:
tnode = node.getElementsByTagName("testcase")[index] tnode = node.getElementsByTagName("testcase")[index]
assert_attr(tnode, assert_attr(tnode,
file="test_failure_escape.py",
line="1",
classname="test_failure_escape", classname="test_failure_escape",
name="test_func[%s]" % char) name="test_func[%s]" % char)
sysout = tnode.getElementsByTagName('system-out')[0] sysout = tnode.getElementsByTagName('system-out')[0]
@ -214,10 +226,14 @@ class TestPython:
assert_attr(node, failures=1, tests=2) assert_attr(node, failures=1, tests=2)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_junit_prefixing.py",
line="0",
classname="xyz.test_junit_prefixing", classname="xyz.test_junit_prefixing",
name="test_func") name="test_func")
tnode = node.getElementsByTagName("testcase")[1] tnode = node.getElementsByTagName("testcase")[1]
assert_attr(tnode, assert_attr(tnode,
file="test_junit_prefixing.py",
line="3",
classname="xyz.test_junit_prefixing." classname="xyz.test_junit_prefixing."
"TestHello", "TestHello",
name="test_hello") name="test_hello")
@ -234,6 +250,8 @@ class TestPython:
assert_attr(node, skips=1, tests=0) assert_attr(node, skips=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_xfailure_function.py",
line="1",
classname="test_xfailure_function", classname="test_xfailure_function",
name="test_xfail") name="test_xfail")
fnode = tnode.getElementsByTagName("skipped")[0] fnode = tnode.getElementsByTagName("skipped")[0]
@ -253,6 +271,8 @@ class TestPython:
assert_attr(node, skips=1, tests=0) assert_attr(node, skips=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_xfailure_xpass.py",
line="1",
classname="test_xfailure_xpass", classname="test_xfailure_xpass",
name="test_xpass") name="test_xpass")
fnode = tnode.getElementsByTagName("skipped")[0] fnode = tnode.getElementsByTagName("skipped")[0]
@ -267,8 +287,10 @@ class TestPython:
assert_attr(node, errors=1, tests=0) assert_attr(node, errors=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_collect_error.py",
#classname="test_collect_error", #classname="test_collect_error",
name="test_collect_error") name="test_collect_error")
assert tnode.getAttributeNode("line") is None
fnode = tnode.getElementsByTagName("error")[0] fnode = tnode.getElementsByTagName("error")[0]
assert_attr(fnode, message="collection failure") assert_attr(fnode, message="collection failure")
assert "SyntaxError" in fnode.toxml() assert "SyntaxError" in fnode.toxml()
@ -281,8 +303,10 @@ class TestPython:
assert_attr(node, skips=1, tests=0) assert_attr(node, skips=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0] tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, assert_attr(tnode,
file="test_collect_skipped.py",
#classname="test_collect_error", #classname="test_collect_error",
name="test_collect_skipped") name="test_collect_skipped")
assert tnode.getAttributeNode("line") is None # py.test doesn't give us a line here.
fnode = tnode.getElementsByTagName("skipped")[0] fnode = tnode.getElementsByTagName("skipped")[0]
assert_attr(fnode, message="collection skipped") assert_attr(fnode, message="collection skipped")
@ -510,6 +534,7 @@ def test_unicode_issue368(testdir):
longrepr = ustr longrepr = ustr
sections = [] sections = []
nodeid = "something" nodeid = "something"
location = 'tests/filename.py', 42, 'TestClass.method'
report = Report() report = Report()
# hopefully this is not too brittle ... # hopefully this is not too brittle ...