Skip to content

Commit e1f3c0f

Browse files
authored
[4.6] Include <testsuites> root tag in generated XML (#5550) (#6295)
[4.6] Include <testsuites> root tag in generated XML (#5550)
2 parents 6465244 + 192f699 commit e1f3c0f

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

changelog/5477.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The XML file produced by ``--junitxml`` now correctly contain a ``<testsuites>`` root element.

src/_pytest/junitxml.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -667,18 +667,17 @@ def pytest_sessionfinish(self):
667667
)
668668
logfile.write('<?xml version="1.0" encoding="utf-8"?>')
669669

670-
logfile.write(
671-
Junit.testsuite(
672-
self._get_global_properties_node(),
673-
[x.to_xml() for x in self.node_reporters_ordered],
674-
name=self.suite_name,
675-
errors=self.stats["error"],
676-
failures=self.stats["failure"],
677-
skipped=self.stats["skipped"],
678-
tests=numtests,
679-
time="%.3f" % suite_time_delta,
680-
).unicode(indent=0)
670+
suite_node = Junit.testsuite(
671+
self._get_global_properties_node(),
672+
[x.to_xml() for x in self.node_reporters_ordered],
673+
name=self.suite_name,
674+
errors=self.stats["error"],
675+
failures=self.stats["failure"],
676+
skipped=self.stats["skipped"],
677+
tests=numtests,
678+
time="%.3f" % suite_time_delta,
681679
)
680+
logfile.write(Junit.testsuites([suite_node]).unicode(indent=0))
682681
logfile.close()
683682

684683
def pytest_terminal_summary(self, terminalreporter):

testing/test_junitxml.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ def find_first_by_tag(self, tag):
4747
def _by_tag(self, tag):
4848
return self.__node.getElementsByTagName(tag)
4949

50+
@property
51+
def children(self):
52+
return [type(self)(x) for x in self.__node.childNodes]
53+
54+
@property
55+
def get_unique_child(self):
56+
children = self.children
57+
assert len(children) == 1
58+
return children[0]
59+
5060
def find_nth_by_tag(self, tag, n):
5161
items = self._by_tag(tag)
5262
try:
@@ -81,7 +91,7 @@ def tag(self):
8191
return self.__node.tagName
8292

8393
@property
84-
def next_siebling(self):
94+
def next_sibling(self):
8595
return type(self)(self.__node.nextSibling)
8696

8797

@@ -390,11 +400,11 @@ def test_fail():
390400
fnode = tnode.find_first_by_tag("failure")
391401
fnode.assert_attr(message="ValueError: 42")
392402
assert "ValueError" in fnode.toxml()
393-
systemout = fnode.next_siebling
403+
systemout = fnode.next_sibling
394404
assert systemout.tag == "system-out"
395405
assert "hello-stdout" in systemout.toxml()
396406
assert "info msg" not in systemout.toxml()
397-
systemerr = systemout.next_siebling
407+
systemerr = systemout.next_sibling
398408
assert systemerr.tag == "system-err"
399409
assert "hello-stderr" in systemerr.toxml()
400410
assert "info msg" not in systemerr.toxml()
@@ -1101,6 +1111,20 @@ def test_x(i):
11011111
assert failed == ["test_x[22]"]
11021112

11031113

1114+
def test_root_testsuites_tag(testdir):
1115+
testdir.makepyfile(
1116+
"""
1117+
def test_x():
1118+
pass
1119+
"""
1120+
)
1121+
_, dom = runandparse(testdir)
1122+
root = dom.get_unique_child
1123+
assert root.tag == "testsuites"
1124+
suite_node = root.get_unique_child
1125+
assert suite_node.tag == "testsuite"
1126+
1127+
11041128
def test_runs_twice(testdir):
11051129
f = testdir.makepyfile(
11061130
"""

0 commit comments

Comments
 (0)