1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
#!/usr/bin/python3
"""
Generate an NUnit XML test report annotated with test issue keys, suitable
for importing into JIRA/X-ray
"""
# NOTE: deliberately avoiding any dependencies outside the standard library!
import argparse
import logging
import sys
from xml.dom import minidom
log = logging.getLogger(__name__)
class TestCase:
"""
Container for the results of an executed test.
"""
def __init__(self, name, success, tests=(), requirements=(),
asserts=1):
self.name = name
self.success = success
self.tests = list(tests)
self.requirements = list(requirements)
self.asserts = asserts
def to_xml(self, doc):
"""Create xml.dom.minidom node in document"""
test = doc.createElement("test-case")
test.setAttribute("name", self.name)
test.setAttribute("executed", "True")
test.setAttribute("time", "0.001")
test.setAttribute("asserts", str(self.asserts))
test.setAttribute("success", str(self.success))
if self.success:
test.setAttribute("result", "Success")
else:
test.setAttribute("result", "Error")
if len(self.tests) > 0 or len(self.requirements) > 0:
properties = doc.createElement("properties")
for test_key in self.tests:
prop = doc.createElement("property")
prop.setAttribute("name", "Test")
prop.setAttribute("value", test_key)
properties.appendChild(prop)
for req in self.requirements:
prop = doc.createElement("property")
prop.setAttribute("name", "Requirement")
prop.setAttribute("value", req)
properties.appendChild(prop)
test.appendChild(properties)
return test
@staticmethod
def from_xml(node):
tests, requirements = [], []
for prop in node.getElementsByTagName("property"):
property_type = prop.getAttribute("name")
if property_type == "Requirement":
requirements.append(prop.getAttribute("value"))
elif property_type == "Test":
tests.append(prop.getAttribute("value"))
return TestCase(
name=node.getAttribute("name"),
success=node.getAttribute("success") == "True",
tests=tests,
requirements=requirements,
asserts=int(node.getAttribute("asserts")))
def create_nunit_xml(test_cases):
"""
Create overall NUnit XML output for a list of test cases
"""
passed = [t.success for t in test_cases].count(True)
failed = [t.success for t in test_cases].count(False)
doc = minidom.Document()
root = doc.createElement("test-results")
root.setAttribute("total", str(passed + failed))
root.setAttribute("failed", str(failed))
root.setAttribute("passed", str(passed))
suite = doc.createElement("test-suite")
attr_result = "Success"
if failed != 0:
attr_result = "Error"
root.setAttribute("result", attr_result)
suite.setAttribute("result", attr_result)
doc.appendChild(root)
root.appendChild(suite)
results = doc.createElement("results")
suite.appendChild(results)
for test_case in test_cases:
results.appendChild(test_case.to_xml(doc))
return doc
def combine_results(xml_files, only_with_properties=False):
"""
Combine multiple NUnit outputs into a single test suite.
:param xml_files: list of NUnit input file names
:param only_with_properties: only output test cases that include one or more property tags (for Bamboo reporting)
"""
test_cases = []
for xml_file in xml_files:
log.info("Reading NUnit report %s", xml_file)
dom = minidom.parse(xml_file)
for node in dom.getElementsByTagName("test-case"):
if only_with_properties:
if len(node.getElementsByTagName("property")) == 0:
continue
test_cases.append(TestCase.from_xml(node))
return create_nunit_xml(test_cases)
def main(argv):
"""Standalone program runner"""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("test_names",
help="Comma-separated list of test names")
parser.add_argument("test_keys",
help="JIRA issue(s) associated with this test (comma-separated list)")
parser.add_argument("--failed", action="store_false", dest="success",
default=True, help="Indicate test failure")
parser.add_argument("--output-xml", action="store",
default="nunit_out.xml",
help="NUnit XML file to write")
args = parser.parse_args(argv)
test_cases = []
for test_name, test_key in zip(args.test_names.split(","),
args.test_keys.split(",")):
test_cases.append(TestCase(test_name, args.success, [test_key]))
doc = create_nunit_xml(test_cases)
with open(args.output_xml, "w") as xml_out:
xml_out.write(doc.toprettyxml(indent=" "))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
|