Add `file` and `line` attributes to junit-xml output.
This adds the `file` and `line` attributes to the junit-xml output which can be used by tooling to identify where tests come from. This can be used for many things such as IDEs jumping to failures and test runners evenly balancing tests among multiple executors. Update test_junitxml.py Foo.
This commit is contained in:
parent
76497c2542
commit
7fa27af408
1
AUTHORS
1
AUTHORS
|
@ -39,6 +39,7 @@ Janne Vanhala
|
|||
Jason R. Coombs
|
||||
Jurko Gospodnetić
|
||||
Katarzyna Jachim
|
||||
Kevin Cox
|
||||
Maciek Fijalkowski
|
||||
Maho
|
||||
Marc Schlaich
|
||||
|
|
|
@ -67,6 +67,8 @@
|
|||
|
||||
- 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)
|
||||
-----------------------------
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
""" 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.
|
||||
"""
|
||||
import py
|
||||
|
@ -93,11 +95,15 @@ class LogXML(object):
|
|||
classnames = names[:-1]
|
||||
if self.prefix:
|
||||
classnames.insert(0, self.prefix)
|
||||
self.tests.append(Junit.testcase(
|
||||
classname=".".join(classnames),
|
||||
name=bin_xml_escape(names[-1]),
|
||||
time=0
|
||||
))
|
||||
attrs = {
|
||||
"classname": ".".join(classnames),
|
||||
"name": bin_xml_escape(names[-1]),
|
||||
"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):
|
||||
for capname in ('out', 'err'):
|
||||
|
|
|
@ -70,6 +70,8 @@ class TestPython:
|
|||
assert_attr(node, errors=1, tests=0)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_setup_error.py",
|
||||
line="2",
|
||||
classname="test_setup_error",
|
||||
name="test_function")
|
||||
fnode = tnode.getElementsByTagName("error")[0]
|
||||
|
@ -88,6 +90,8 @@ class TestPython:
|
|||
assert_attr(node, skips=1)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_skip_contains_name_reason.py",
|
||||
line="1",
|
||||
classname="test_skip_contains_name_reason",
|
||||
name="test_skip")
|
||||
snode = tnode.getElementsByTagName("skipped")[0]
|
||||
|
@ -108,6 +112,8 @@ class TestPython:
|
|||
assert_attr(node, failures=1)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_classname_instance.py",
|
||||
line="1",
|
||||
classname="test_classname_instance.TestClass",
|
||||
name="test_method")
|
||||
|
||||
|
@ -120,6 +126,8 @@ class TestPython:
|
|||
assert_attr(node, failures=1)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file=os.path.join("sub", "test_hello.py"),
|
||||
line="0",
|
||||
classname="sub.test_hello",
|
||||
name="test_func")
|
||||
|
||||
|
@ -151,6 +159,8 @@ class TestPython:
|
|||
assert_attr(node, failures=1, tests=1)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_failure_function.py",
|
||||
line="1",
|
||||
classname="test_failure_function",
|
||||
name="test_fail")
|
||||
fnode = tnode.getElementsByTagName("failure")[0]
|
||||
|
@ -193,6 +203,8 @@ class TestPython:
|
|||
|
||||
tnode = node.getElementsByTagName("testcase")[index]
|
||||
assert_attr(tnode,
|
||||
file="test_failure_escape.py",
|
||||
line="1",
|
||||
classname="test_failure_escape",
|
||||
name="test_func[%s]" % char)
|
||||
sysout = tnode.getElementsByTagName('system-out')[0]
|
||||
|
@ -214,10 +226,14 @@ class TestPython:
|
|||
assert_attr(node, failures=1, tests=2)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_junit_prefixing.py",
|
||||
line="0",
|
||||
classname="xyz.test_junit_prefixing",
|
||||
name="test_func")
|
||||
tnode = node.getElementsByTagName("testcase")[1]
|
||||
assert_attr(tnode,
|
||||
file="test_junit_prefixing.py",
|
||||
line="3",
|
||||
classname="xyz.test_junit_prefixing."
|
||||
"TestHello",
|
||||
name="test_hello")
|
||||
|
@ -234,6 +250,8 @@ class TestPython:
|
|||
assert_attr(node, skips=1, tests=0)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_xfailure_function.py",
|
||||
line="1",
|
||||
classname="test_xfailure_function",
|
||||
name="test_xfail")
|
||||
fnode = tnode.getElementsByTagName("skipped")[0]
|
||||
|
@ -253,6 +271,8 @@ class TestPython:
|
|||
assert_attr(node, skips=1, tests=0)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_xfailure_xpass.py",
|
||||
line="1",
|
||||
classname="test_xfailure_xpass",
|
||||
name="test_xpass")
|
||||
fnode = tnode.getElementsByTagName("skipped")[0]
|
||||
|
@ -267,8 +287,10 @@ class TestPython:
|
|||
assert_attr(node, errors=1, tests=0)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_collect_error.py",
|
||||
#classname="test_collect_error",
|
||||
name="test_collect_error")
|
||||
assert tnode.getAttributeNode("line") is None
|
||||
fnode = tnode.getElementsByTagName("error")[0]
|
||||
assert_attr(fnode, message="collection failure")
|
||||
assert "SyntaxError" in fnode.toxml()
|
||||
|
@ -281,8 +303,10 @@ class TestPython:
|
|||
assert_attr(node, skips=1, tests=0)
|
||||
tnode = node.getElementsByTagName("testcase")[0]
|
||||
assert_attr(tnode,
|
||||
file="test_collect_skipped.py",
|
||||
#classname="test_collect_error",
|
||||
name="test_collect_skipped")
|
||||
assert tnode.getAttributeNode("line") is None # py.test doesn't give us a line here.
|
||||
fnode = tnode.getElementsByTagName("skipped")[0]
|
||||
assert_attr(fnode, message="collection skipped")
|
||||
|
||||
|
@ -510,6 +534,7 @@ def test_unicode_issue368(testdir):
|
|||
longrepr = ustr
|
||||
sections = []
|
||||
nodeid = "something"
|
||||
location = 'tests/filename.py', 42, 'TestClass.method'
|
||||
report = Report()
|
||||
|
||||
# hopefully this is not too brittle ...
|
||||
|
|
Loading…
Reference in New Issue