winIDEA SDK
junitreport.py
1# This script is licensed under BSD License, see file LICENSE.txt.
2#
3# (c) TASKING Germany GmbH, 2023
4
5"""
6This script can be used to write test results to XML file in JUnit
7format. Not all tags supported by JUnit are provided, but the script
8can easily be expanded to support them.
9
10See function main() below for example of usage.
11"""
12
13
14
15class TestResult:
16 """
17 This class contains result of one test case.
18 """
19
20 def __init__(self, testId, testedItem,
21 isError=False,
22 isFailure=False,
23 errorFailureType='',
24 errorFailureDesc=''):
25
26 self._testId = testId
27 self._testedItem = testedItem
28 self._isError = isError
29 self._isFailure = isFailure
30 self._errorFailureType = errorFailureType
31 self._errorFailureDesc = errorFailureDesc
32
33 def getTestId(self):
34 return self._testId
35
36 def getTestedItem(self):
37 return self._testedItem
38
39 def isError(self):
40 return self._isError
41
42 def isFailure(self):
43 return self._isFailure
44
45 def getErrorFailureType(self):
46 return self._errorFailureType
47
48 def getErrorFailureDesc(self):
49 return self._errorFailureDesc
50
51
52class _TestReportStatistics:
53 """
54 This class contains test statistics. For internal usage only.
55 """
56 def __init__(self, noOfErrors, noOfFailures):
57 self._noOfErrors = noOfErrors
58 self._noOfFailures = noOfFailures
59
60 def getNoOfErrors(self):
61 return self._noOfErrors
62
63 def getNoOfFailures(self):
64 return self._noOfFailures
65
66
67def saveTestResultsAsJUnit(fileName, testSuiteName, testResults):
68 """
69 This method saves test results in Junit format, so that it can be parsed
70 by Jenkins/Hudson. This method creates file with one test suite.
71
72 For details about the format see:
73 https://stackoverflow.com/questions/4922867/junit-xml-format-specification-that-hudson-supports
74
75 XSD:
76 https://svn.jenkins-ci.org/trunk/hudson/dtkit/dtkit-format/dtkit-junit-model/src/main/resources/com/thalesgroup/dtkit/junit/model/xsd/junit-4.xsd
77
78 Parameters:
79
80 fileName - name of file to save report to
81 testSuiteName - name of test suite which is used for attribute name:
82 '<testsuite name="' + testSuiteName + '" ...
83 testResults - list of TestResult instances
84
85 Example of generated file:
86 <testsuites name="testIDEATestSuite" tests="3" errors="0" failures="0">
87 <testsuite name="testIDEATestSuite" tests="3" errors="0" failures="0">
88 <testcase classname="add_int" name="test-0"/>
89 <testcase classname="add_int" name="test-1"
90 <error type="exception"/>Invalid value!</error>
91 </testcase>
92 <testcase classname="max_int" name="test-2">
93 <failure type="expression"></failure>
94 </testcase>
95 </testsuite>
96 </testsuites>
97 """
98
99 reportStats = _getReportStatistics(testResults)
100
101 with open(fileName, 'w') as of:
102 _saveTestResultsAsJUnitStart(of,
103 testSuiteName,
104 len(testResults),
105 reportStats.getNoOfErrors(),
106 reportStats.getNoOfFailures())
107
108 _saveTestResultsAsJUnitForTestSuite(of,
109 testSuiteName,
110 testResults,
111 reportStats)
112 _saveTestResultsAsJUnitEnd(of)
113
114
115def _saveTestResultsAsJUnitStart(of, testSuitesName, noOfTests, noOfErrors,
116 noOfFailures):
117 """
118 This method saves test results in Junit format, so that it can be parsed
119 by Jenkins/Hudson. Typical usage:
120
121 saveTestResultsAsJUnitStart(...)
122 saveTestResultsAsJUnitForTestSuite(...)
123 saveTestResultsAsJUnitEnd()
124
125
126 Parameters:
127 of - opened file stream
128 testSuitesName - values for the 'name' attribute of tags 'testsuites' and
129 'testsuite'
130 noOfTests - number of all tests in test suite
131 noOfErrors - number of errors
132 noOfFailures - number of failures
133
134 For details about format see method _saveTestResultsAsJUnit().
135 """
136
137 of.write('<?xml version="1.0" encoding="UTF-8"?>\n')
138
139 of.write('<testsuites name="' + testSuitesName + '" tests="' +
140 str(noOfTests) + '" errors="' +
141 str(noOfErrors) + '" failures="' +
142 str(noOfFailures) + '">\n')
143
144
145def _saveTestResultsAsJUnitForTestSuite(of, testSuiteName, testResults, reportStats):
146 """
147 This method saves test results in JUnit format, so that it can be parsed
148 by Jenkins/Hudson for one test suite. Typical usage:
149
150 saveTestResultsAsJUnitStart(...)
151 saveTestResultsAsJUnitForTestSuite(...)
152 saveTestResultsAsJUnitEnd()
153
154 See method _saveTestResultsAsJUnitStart() for details.
155 """
156
157 of.write(' <testsuite name="' + testSuiteName + '" tests="' +
158 str(len(testResults)) + '" errors="' +
159 str(reportStats.getNoOfErrors()) + '" failures="' +
160 str(reportStats.getNoOfFailures()) + '">\n')
161
162 for tr in testResults:
163
164 of.write(' <testcase classname="' + tr.getTestedItem() + '" name="' +
165 tr.getTestId() + '">\n')
166
167 if tr.isError():
168 of.write(' <error type="' + tr.getErrorFailureType() + '">')
169 of.write(_replaceXMLEntities(tr.getErrorFailureDesc()))
170 of.write('</error>\n')
171
172 if tr.isFailure():
173 of.write(' <failure type="' + tr.getErrorFailureType() + '">')
174 of.write(_replaceXMLEntities(tr.getErrorFailureDesc()))
175 of.write('</failure>\n')
176
177 of.write(' </testcase>\n')
178 of.write(' </testsuite>\n')
179
180
181def _saveTestResultsAsJUnitEnd(of):
182 """
183 This method adds the last tag to XML file in Jenkins/Hudson format.
184 See method saveTestResultsAsJUnitStart() for details.
185 """
186 of.write('</testsuites>\n')
187
188
189def _getReportStatistics(testResults):
190
191 noOfErrors = 0
192 noOfFailures = 0
193
194 for tr in testResults:
195
196 if tr.isError():
197 noOfErrors += 1
198
199 if tr.isFailure():
200 noOfFailures += 1
201
202 return _TestReportStatistics(noOfErrors, noOfFailures)
203
204
205
206def _replaceXMLEntities(message):
207 message = message.replace('<', '&lt;')
208 message = message.replace('>', '&gt;')
209 message = message.replace('&', '&amp;')
210 message = message.replace('"', '&quot;')
211 message = message.replace("'", '&apos;')
212 return message
213
214
215def main():
216 """
217 This function demonstrates usage of this module.
218 """
219
220 # Let's create a list of test results
221 testResults = [TestResult('test-01', 'HandBrake'),
222 TestResult('test-02', 'HandBrake'),
223 TestResult('test-03', 'HandBrake', isFailure = True,
224 errorFailureType='expression',
225 errorFailureDesc='voltage < 3.14'),
226
227 TestResult('test-03', 'HandBrake', isError = True,
228 errorFailureType='exception',
229 errorFailureDesc='FileNotFoundException')
230 ]
231
232 # Save results
233 outFName = 'testReport.xml'
234 saveTestResultsAsJUnit(outFName, 'iSYSTEM HIL test', testResults)
235 print("Sample report saved to '" + outFName + "'")
236
237
238if __name__ == '__main__':
239 main()