test_parallel.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import pickle
  2. import sys
  3. import unittest
  4. from django.test import SimpleTestCase
  5. from django.test.runner import RemoteTestResult
  6. from django.utils.version import PY311, PY312
  7. try:
  8. import tblib.pickling_support
  9. except ImportError:
  10. tblib = None
  11. class ExceptionThatFailsUnpickling(Exception):
  12. """
  13. After pickling, this class fails unpickling with an error about incorrect
  14. arguments passed to __init__().
  15. """
  16. def __init__(self, arg):
  17. super().__init__()
  18. class ParallelTestRunnerTest(SimpleTestCase):
  19. """
  20. End-to-end tests of the parallel test runner.
  21. These tests are only meaningful when running tests in parallel using
  22. the --parallel option, though it doesn't hurt to run them not in
  23. parallel.
  24. """
  25. def test_subtest(self):
  26. """
  27. Passing subtests work.
  28. """
  29. for i in range(2):
  30. with self.subTest(index=i):
  31. self.assertEqual(i, i)
  32. class SampleFailingSubtest(SimpleTestCase):
  33. # This method name doesn't begin with "test" to prevent test discovery
  34. # from seeing it.
  35. def dummy_test(self):
  36. """
  37. A dummy test for testing subTest failures.
  38. """
  39. for i in range(3):
  40. with self.subTest(index=i):
  41. self.assertEqual(i, 1)
  42. class RemoteTestResultTest(SimpleTestCase):
  43. def _test_error_exc_info(self):
  44. try:
  45. raise ValueError("woops")
  46. except ValueError:
  47. return sys.exc_info()
  48. def test_was_successful_no_events(self):
  49. result = RemoteTestResult()
  50. self.assertIs(result.wasSuccessful(), True)
  51. def test_was_successful_one_success(self):
  52. result = RemoteTestResult()
  53. result.addSuccess(None)
  54. self.assertIs(result.wasSuccessful(), True)
  55. def test_was_successful_one_expected_failure(self):
  56. result = RemoteTestResult()
  57. result.addExpectedFailure(None, self._test_error_exc_info())
  58. self.assertIs(result.wasSuccessful(), True)
  59. def test_was_successful_one_skip(self):
  60. result = RemoteTestResult()
  61. result.addSkip(None, "Skipped")
  62. self.assertIs(result.wasSuccessful(), True)
  63. @unittest.skipUnless(tblib is not None, "requires tblib to be installed")
  64. def test_was_successful_one_error(self):
  65. result = RemoteTestResult()
  66. result.addError(None, self._test_error_exc_info())
  67. self.assertIs(result.wasSuccessful(), False)
  68. @unittest.skipUnless(tblib is not None, "requires tblib to be installed")
  69. def test_was_successful_one_failure(self):
  70. result = RemoteTestResult()
  71. result.addFailure(None, self._test_error_exc_info())
  72. self.assertIs(result.wasSuccessful(), False)
  73. def test_picklable(self):
  74. result = RemoteTestResult()
  75. loaded_result = pickle.loads(pickle.dumps(result))
  76. self.assertEqual(result.events, loaded_result.events)
  77. def test_pickle_errors_detection(self):
  78. picklable_error = RuntimeError("This is fine")
  79. not_unpicklable_error = ExceptionThatFailsUnpickling("arg")
  80. result = RemoteTestResult()
  81. result._confirm_picklable(picklable_error)
  82. msg = "__init__() missing 1 required positional argument"
  83. with self.assertRaisesMessage(TypeError, msg):
  84. result._confirm_picklable(not_unpicklable_error)
  85. @unittest.skipUnless(tblib is not None, "requires tblib to be installed")
  86. def test_add_failing_subtests(self):
  87. """
  88. Failing subtests are added correctly using addSubTest().
  89. """
  90. # Manually run a test with failing subtests to prevent the failures
  91. # from affecting the actual test run.
  92. result = RemoteTestResult()
  93. subtest_test = SampleFailingSubtest(methodName="dummy_test")
  94. subtest_test.run(result=result)
  95. events = result.events
  96. # addDurations added in Python 3.12.
  97. if PY312:
  98. self.assertEqual(len(events), 5)
  99. else:
  100. self.assertEqual(len(events), 4)
  101. self.assertIs(result.wasSuccessful(), False)
  102. event = events[1]
  103. self.assertEqual(event[0], "addSubTest")
  104. self.assertEqual(
  105. str(event[2]),
  106. "dummy_test (test_runner.test_parallel.SampleFailingSubtest%s) (index=0)"
  107. # Python 3.11 uses fully qualified test name in the output.
  108. % (".dummy_test" if PY311 else ""),
  109. )
  110. self.assertEqual(repr(event[3][1]), "AssertionError('0 != 1')")
  111. event = events[2]
  112. self.assertEqual(repr(event[3][1]), "AssertionError('2 != 1')")
  113. @unittest.skipUnless(PY312, "unittest --durations option requires Python 3.12")
  114. def test_add_duration(self):
  115. result = RemoteTestResult()
  116. result.addDuration(None, 2.3)
  117. self.assertEqual(result.collectedDurations, [("None", 2.3)])