Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
junitxml: add properties node in testsuite level
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 dbbd9fb
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 1 deletion.
1 change: 1 addition & 0 deletions AUTHORS
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
4 changes: 3 additions & 1 deletion CHANGELOG.rst
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 `#1446`_).


*

Expand Down
21 changes: 21 additions & 0 deletions _pytest/junitxml.py
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
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 dbbd9fb

Please sign in to comment.