Skip to content

Commit

Permalink
junitxml: add properties node in testsuite level
Browse files Browse the repository at this point in the history
The commit allow users to add a properties node in testsuite level see
example below:

<testsuite errors="0" failures="0" name="pytest" skips="1" tests="1"
time="11.824">
  <properties>
    <property name="ARCH" value="PPC"/>
    <property name="OS" value="RHEL 7.2"/>
    <property name="TestPlanURL" value="https://url.."/>
    <property name="Automated" value="True"/>
  </properties>
  <testcase classname="git.....>
  </testcase>
</testsuite>

The current situation is that properties node can be added to every
testcase node. However, sometimes we need some global properties that
applies to all testcases and give better description for the testsuite
itself.
  • Loading branch information
tareqalayan committed Mar 15, 2016
1 parent 0cacdef commit fd11b56
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 2 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Ronny Pfannschmidt
Ross Lawley
Ryan Wooden
Samuele Pedroni
Tareq Alayan
Tom Viner
Trevor Bekolay
Wouter van Ackooy
Expand Down
6 changes: 4 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
for a fixture (to solve the funcarg-shadowing-fixture problem).
Thanks `@novas0x2a`_ for the complete PR (`#1444`_).

*
* New Add ability to add global properties in the final xunit output file.
Thanks `@tareqalayan`_ for the complete PR `#1454`_).


*

Expand All @@ -29,7 +31,7 @@

.. _#1428: https://github.com/pytest-dev/pytest/pull/1428
.. _#1444: https://github.com/pytest-dev/pytest/pull/1444

.. _#1454: https://github.com/pytest-dev/pytest/pull/1454

2.9.1.dev1
==========
Expand Down
21 changes: 21 additions & 0 deletions _pytest/junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ def __init__(self, logfile, prefix):
], 0)
self.node_reporters = {} # nodeid -> _NodeReporter
self.node_reporters_ordered = []
self.global_properties = []

def finalize(self, report):
nodeid = getattr(report, 'nodeid', report)
Expand All @@ -273,9 +274,12 @@ def node_reporter(self, report):
if key in self.node_reporters:
# TODO: breasks for --dist=each
return self.node_reporters[key]

reporter = _NodeReporter(nodeid, self)

self.node_reporters[key] = reporter
self.node_reporters_ordered.append(reporter)

return reporter

def add_stats(self, key):
Expand Down Expand Up @@ -361,7 +365,9 @@ def pytest_sessionfinish(self):
numtests = self.stats['passed'] + self.stats['failure']

logfile.write('<?xml version="1.0" encoding="utf-8"?>')

logfile.write(Junit.testsuite(
self._get_global_properties_node(),
[x.to_xml() for x in self.node_reporters_ordered],
name="pytest",
errors=self.stats['error'],
Expand All @@ -374,3 +380,18 @@ def pytest_sessionfinish(self):
def pytest_terminal_summary(self, terminalreporter):
terminalreporter.write_sep("-",
"generated xml file: %s" % (self.logfile))

def add_global_property(self, name, value):
self.global_properties.append((str(name), bin_xml_escape(value)))

def _get_global_properties_node(self):
"""Return a Junit node containing custom properties, if any.
"""
if self.global_properties:
return Junit.properties(
[
Junit.property(name=name, value=value)
for name, value in self.global_properties
]
)
return ''
41 changes: 41 additions & 0 deletions testing/test_junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -783,3 +783,44 @@ def test_pass():
u'test_fancy_items_regression test_pass'
u' test_fancy_items_regression.py',
]


def test_global_properties(testdir):
path = testdir.tmpdir.join("test_global_properties.xml")
log = LogXML(str(path), None)
from _pytest.runner import BaseReport

class Report(BaseReport):
sections = []
nodeid = "test_node_id"

log.pytest_sessionstart()
log.add_global_property('foo', 1)
log.add_global_property('bar', 2)
log.pytest_sessionfinish()

dom = minidom.parse(str(path))

properties = dom.getElementsByTagName('properties')

assert (properties.length == 1), "There must be one <properties> node"

property_list = dom.getElementsByTagName('property')

assert (property_list.length == 2), "There most be only 2 property nodes"

expected = {'foo': '1', 'bar': '2'}
actual = {}

for p in property_list:
k = str(p.getAttribute('name'))
v = str(p.getAttribute('value'))
actual[k] = v

assert (len(actual.keys()) == len(expected.keys()))

for key, value in list(actual.items()):
if key in expected and expected[k] == v:
continue
else:
assert False, "Actual : %s != expected: %s" % (actual, expected)

0 comments on commit fd11b56

Please sign in to comment.