Advertisement
Guest User

Untitled

a guest
Jul 16th, 2019
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.04 KB | None | 0 0
  1. ##
  2. # Print JUnit Test Results.
  3. #
  4. # - Description: Only prints iOS-formatted results (AllTests > Suites > Subsuites > Cases).
  5. #
  6. # - Usage:
  7. # - `python3 PrintBluepillJUnitResults.py <XML file>`
  8. #
  9. # - Arguments:
  10. # - JUnit results XML file
  11. # - [optional] Format (e.g. "terminal" or "slack") (default: "terminal")
  12. #
  13. # - Dependencies:
  14. # - Python 3
  15. # - Requires junitparser (`pip3 install junitparser`)
  16. ##
  17.  
  18. import sys
  19. from junitparser import TestCase, TestSuite, JUnitXml, Skipped, Error, Failure
  20.  
  21. class TestError(object):
  22. """A nice error wrapper
  23.  
  24. Properties:
  25. - name e.g. "MyCareTeamTests/testRemoveFromMyCareTeam"
  26.  
  27. Attributes:
  28. - type e.g. "Failure" or "Error"
  29. - message e.g. "No matches found for first match sequence"
  30. - location e.g. "XCUIElement+Extension.swift:122"
  31. - trace Full stacktrace (as reported by XCTest)
  32. """
  33.  
  34. def __init__(self, testCase, error):
  35. self.name = "{}/{}".format(testCase.classname, testCase.name)
  36. self.message = error.message
  37. self.type = error.type
  38. self.location = stripAndRemoveNewlines(error._elem.text)
  39. self.trace = stripAndRemoveNewlines(testCase.system_out)
  40.  
  41. def __eq__(self, other):
  42. return self.uniqueId==other.uniqueId
  43.  
  44. def __hash__(self):
  45. return hash(self.uniqueId)
  46.  
  47. @property
  48. def uniqueId(self):
  49. """Used for mapping duplicate failures on the same test case.
  50.  
  51. Bluepill runs will often retry failed tests.
  52. String in format: "MyCareTeamTests/testAddToMyCareTeam:Out of bounds exception"
  53. """
  54. return "{}:{}".format(self.name, self.message)
  55.  
  56. class BluepillJUnitReport(JUnitXml):
  57. """Fix baby"""
  58. def __iter__(self):
  59. return super(JUnitXml, self).iterchildren(ParentTestSuite)
  60.  
  61. class ParentTestSuite(TestSuite):
  62. """Fix baby"""
  63. def __iter__(self):
  64. return super(TestSuite, self).iterchildren(TestSuite)
  65.  
  66. def stripAndRemoveNewlines(text):
  67. """Removes empty newlines, and removes leading whitespace.
  68. """
  69. no_empty_newlines = "\n".join([ll.rstrip() for ll in text.splitlines() if ll.strip()])
  70. return no_empty_newlines.strip()
  71.  
  72. def getLastXLines(string, x):
  73. return "\n".join(string.split("\n")[-x:])
  74.  
  75. def getTestErrors(testSuites):
  76. """Get a collection of bad results in these test suites
  77. """
  78.  
  79. if testSuites.errors == 0 and testSuites.failures == 0:
  80. return [] # early exit
  81.  
  82. testErrors = []
  83.  
  84. # Suites (e.g. "UITests.xctest")
  85. for testSuite in testSuites:
  86. if testSuite.errors == 0 and testSuite.failures == 0:
  87. continue # skip
  88.  
  89. # Groups (e.g. "MarketplaceTests")
  90. for testGroup in testSuite:
  91. if testGroup.errors == 0 and testGroup.failures == 0:
  92. continue # skip
  93.  
  94. # (e.g. "testOpenXMLReader")
  95. for testCase in testGroup:
  96. testResult = testCase.result
  97.  
  98. if isinstance(testResult, Error) or isinstance(testResult, Failure):
  99. testError = TestError(testCase, testResult)
  100. testErrors.append(testError)
  101.  
  102. return testErrors
  103.  
  104. def printForTerminal(testErrors):
  105. """Formatted for terminal
  106.  
  107. MyCareTeamTests/testAddToMyCareTeamButton (1)
  108. Error: "No matches found for first match sequence"
  109. Location: XCUIElement+Extension.swift:122
  110. Trackback:
  111. XCTestOutputBarrier t = 14.25s Assertion Failure: XCUIElement+Extension.swift:122: No matches found for first match sequence (
  112. "<XCTElementFilteringTransformer: 0x6000009d7f90 'Find: Descendants matching type Button'>",
  113. "<XCTElementFilteringTransformer: 0x6000009e4360 'Find: Elements matching predicate '\"Book\" IN identifiers''>"
  114. ) from input
  115. t = 14.32s Tear Down
  116. """
  117. uniqueTestErrors = set(testErrors)
  118.  
  119. if len(testErrors) == 0:
  120. print("All tests passed.")
  121. else:
  122. print("There were {} errors/failures ({} unique):\n".format(len(testErrors),
  123. len(uniqueTestErrors)))
  124.  
  125. for error in uniqueTestErrors:
  126. occurences = testErrors.count(error)
  127.  
  128. print("""\n{e.name} ({occurences})
  129. {e.type}: \t\t"{e.message}"
  130. Location: \t{e.location}
  131. Traceback:\n{trace}\n""".format(e=error,
  132. occurences=occurences,
  133. trace=error.trace))
  134.  
  135. def printForSlack(testErrors):
  136. """Formatted for slack
  137.  
  138. MyCareTeamTests/testAddToMyCareTeamButton (1)
  139. Error: "No matches found for first match sequence"
  140. Location: XCUIElement+Extension.swift:122
  141. Trackback:
  142. XCTestOutputBarrier t = 14.25s Assertion Failure: XCUIElement+Extension.swift:122: No matches found for first match sequence (
  143. "<XCTElementFilteringTransformer: 0x6000009d7f90 'Find: Descendants matching type Button'>",
  144. "<XCTElementFilteringTransformer: 0x6000009e4360 'Find: Elements matching predicate '\"Book\" IN identifiers''>"
  145. ) from input
  146. t = 14.32s Tear Down
  147. """
  148. uniqueTestErrors = set(testErrors)
  149.  
  150. if len(testErrors) == 0:
  151. print("All tests passed.")
  152. else:
  153. print("There were {} errors/failures ({} unique):\n".format(len(testErrors),
  154. len(uniqueTestErrors)))
  155.  
  156. for error in uniqueTestErrors:
  157. occurences = testErrors.count(error)
  158.  
  159. print(""">*{e.name} ({occurences})*
  160. >{e.message}
  161. >```{trace}```\n""".format(e=error,
  162. occurences=occurences,
  163. trace=getLastXLines(error.trace, 5)))
  164.  
  165. def main():
  166. """python3 PrintBluepillJUnitResults.py <bluepill_junit_result_file.xml>
  167. """
  168.  
  169. if len(sys.argv) < 2:
  170. print("Missing argument 1: Input file")
  171.  
  172. file = sys.argv[1]
  173. results = BluepillJUnitReport.fromfile(file)
  174. testErrors = getTestErrors(results)
  175.  
  176.  
  177. if len(sys.argv) < 3:
  178. mode = "terminal"
  179. else:
  180. mode = sys.argv[2]
  181.  
  182. if mode == "slack":
  183. printForSlack(testErrors)
  184. else:
  185. printForTerminal(testErrors)
  186.  
  187. if __name__ == "__main__":
  188. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement