File: nunit.py

package info (click to toggle)
python-pbcommand 2.1.1%2Bgit20220616.3f2e6c2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 940 kB
  • sloc: python: 6,929; makefile: 220; sh: 71
file content (143 lines) | stat: -rw-r--r-- 5,240 bytes parent folder | download | duplicates (3)
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:]))