1
2
3
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
83 '<testsuite name="' + testSuiteName + '" ...
84
85 testResults - list of TestResult instances
86
87 Example of generated file::
88
89 <testsuites name="testIDEATestSuite" tests="3" errors="0" failures="0">
90 <testsuite name="testIDEATestSuite" tests="3" errors="0" failures="0">
91 <testcase classname="add_int" name="test-0"/>
92 <testcase classname="add_int" name="test-1"
93 <error type="exception"/>Invalid value!</error>
94 </testcase>
95 <testcase classname="max_int" name="test-2">
96 <failure type="expression"></failure>
97 </testcase>
98 </testsuite>
99 </testsuites>
100
101 """
102
103 reportStats = _getReportStatistics(testResults)
104
105 with open(fileName, 'w') as of:
106 _saveTestResultsAsJUnitStart(of,
107 testSuiteName,
108 len(testResults),
109 reportStats.getNoOfErrors(),
110 reportStats.getNoOfFailures())
111
112 _saveTestResultsAsJUnitForTestSuite(of,
113 testSuiteName,
114 testResults,
115 reportStats)
116 _saveTestResultsAsJUnitEnd(of)
117
118
119def _saveTestResultsAsJUnitStart(of, testSuitesName, noOfTests, noOfErrors,
120 noOfFailures):
121 """
122 This method saves test results in Junit format, so that it can be parsed
123 by Jenkins/Hudson. Typical usage:
124
125 saveTestResultsAsJUnitStart(...)
126 saveTestResultsAsJUnitForTestSuite(...)
127 saveTestResultsAsJUnitEnd()
128
129
130 Parameters:
131 of - opened file stream
132 testSuitesName - values for the 'name' attribute of tags 'testsuites' and
133 'testsuite'
134 noOfTests - number of all tests in test suite
135 noOfErrors - number of errors
136 noOfFailures - number of failures
137
138 For details about format see method _saveTestResultsAsJUnit().
139 """
140
141 of.write('<?xml version="1.0" encoding="UTF-8"?>\n')
142
143 of.write('<testsuites name="' + testSuitesName + '" tests="' +
144 str(noOfTests) + '" errors="' +
145 str(noOfErrors) + '" failures="' +
146 str(noOfFailures) + '">\n')
147
148
149def _saveTestResultsAsJUnitForTestSuite(of, testSuiteName, testResults, reportStats):
150 """
151 This method saves test results in JUnit format, so that it can be parsed
152 by Jenkins/Hudson for one test suite. Typical usage:
153
154 saveTestResultsAsJUnitStart(...)
155 saveTestResultsAsJUnitForTestSuite(...)
156 saveTestResultsAsJUnitEnd()
157
158 See method _saveTestResultsAsJUnitStart() for details.
159 """
160
161 of.write(' <testsuite name="' + testSuiteName + '" tests="' +
162 str(len(testResults)) + '" errors="' +
163 str(reportStats.getNoOfErrors()) + '" failures="' +
164 str(reportStats.getNoOfFailures()) + '">\n')
165
166 for tr in testResults:
167
168 of.write(' <testcase classname="' + tr.getTestedItem() + '" name="' +
169 tr.getTestId() + '">\n')
170
171 if tr.isError():
172 of.write(' <error type="' + tr.getErrorFailureType() + '">')
173 of.write(_replaceXMLEntities(tr.getErrorFailureDesc()))
174 of.write('</error>\n')
175
176 if tr.isFailure():
177 of.write(' <failure type="' + tr.getErrorFailureType() + '">')
178 of.write(_replaceXMLEntities(tr.getErrorFailureDesc()))
179 of.write('</failure>\n')
180
181 of.write(' </testcase>\n')
182 of.write(' </testsuite>\n')
183
184
185def _saveTestResultsAsJUnitEnd(of):
186 """
187 This method adds the last tag to XML file in Jenkins/Hudson format.
188 See method saveTestResultsAsJUnitStart() for details.
189 """
190 of.write('</testsuites>\n')
191
192
193def _getReportStatistics(testResults):
194
195 noOfErrors = 0
196 noOfFailures = 0
197
198 for tr in testResults:
199
200 if tr.isError():
201 noOfErrors += 1
202
203 if tr.isFailure():
204 noOfFailures += 1
205
206 return _TestReportStatistics(noOfErrors, noOfFailures)
207
208
209
210def _replaceXMLEntities(message):
211 message = message.replace('<', '<')
212 message = message.replace('>', '>')
213 message = message.replace('&', '&')
214 message = message.replace('"', '"')
215 message = message.replace("'", ''')
216 return message
217
218
219def main():
220 """
221 This function demonstrates usage of this module.
222 """
223
224
225 testResults = [TestResult('test-01', 'HandBrake'),
226 TestResult('test-02', 'HandBrake'),
227 TestResult('test-03', 'HandBrake', isFailure = True,
228 errorFailureType='expression',
229 errorFailureDesc='voltage < 3.14'),
230
231 TestResult('test-03', 'HandBrake', isError = True,
232 errorFailureType='exception',
233 errorFailureDesc='FileNotFoundException')
234 ]
235
236
237 outFName = 'testReport.xml'
238 saveTestResultsAsJUnit(outFName, 'iSYSTEM HIL test', testResults)
239 print("Sample report saved to '" + outFName + "'")
240
241
242if __name__ == '__main__':
243 main()