checker.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. '''
  2. A simplified version of the unittest module, adapted to run unit tests on data sets instead of code.
  3. @author: olivier.massot, 2018
  4. '''
  5. import inspect
  6. import sys
  7. UNKNOWN = 0
  8. SUCCESS = 1
  9. FAILURE = 2
  10. ERROR = 3
  11. _result_to_str = {UNKNOWN: 'Inconnu',
  12. SUCCESS: 'Succès',
  13. FAILURE: 'Echec',
  14. ERROR: 'Erreur'}
  15. class TestError():
  16. def __init__(self, message, info = {}, critical=False):
  17. self.message = message
  18. self.info = info
  19. self.critical = critical
  20. def __repr__(self):
  21. return f"TestError<message='{self.message}'; info={self.info}; critical={self.critical}>"
  22. class TestResult():
  23. def __init__(self, test):
  24. self._test = test
  25. self._name = ""
  26. self._status = UNKNOWN
  27. self.errors = []
  28. self._exc_info = None
  29. @property
  30. def name(self):
  31. return self._name or self._test.__name__[5:]
  32. @property
  33. def title(self):
  34. return self._test.__doc__.split("\n")[0].strip()
  35. @property
  36. def description(self):
  37. return self._test.__doc__.strip()
  38. @property
  39. def status(self):
  40. return self._status
  41. @property
  42. def status_str(self):
  43. return _result_to_str[self._status]
  44. def __repr__(self):
  45. return f"TestResult<title='{self.title}'; status={self.status}; name={self.name}; method={self._test.__name__}; errors_count={len(self.errors)}>"
  46. def log_error(self, message, info={}):
  47. self._status = FAILURE
  48. error = TestError(message, info)
  49. self.errors.append(error)
  50. def handle_exception(self):
  51. self._status = ERROR
  52. error = TestError("Une erreur inconnue s'est produite, veuillez consulter les fichiers de journalisation.",
  53. {"exc_info": sys.exc_info()})
  54. self.errors.append(error)
  55. class BaseChecker():
  56. def __init__(self):
  57. self._test_running = None
  58. def setUp(self):
  59. pass
  60. def tearDown(self):
  61. pass
  62. def log_error(self, message, **info):
  63. self._test_running.log_error(message, info)
  64. def run(self):
  65. tests_results = []
  66. for mname, m in inspect.getmembers(self, predicate=inspect.ismethod):
  67. if mname[:5] == 'test_':
  68. r = TestResult(m)
  69. self._test_running = r
  70. self.setUp()
  71. try:
  72. m()
  73. except:
  74. r.handle_exception()
  75. self.tearDown()
  76. tests_results.append(r)
  77. if any(err.critical for err in r.errors):
  78. break
  79. return tests_results
  80. if __name__ == '__main__':
  81. class ExampleChecker(BaseChecker):
  82. def test_a(self):
  83. """ Test 1 """
  84. for i in range(10):
  85. self.log_error(f"error-{i}", {"i": i})
  86. def test_b(self):
  87. """ Test 2
  88. some longer description """
  89. return
  90. ch = ExampleChecker()
  91. results = ch.run()
  92. for r in results:
  93. print(r)
  94. for e in r.errors:
  95. print(e)