orionis 0.283.0__py3-none-any.whl → 0.285.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. orionis/foundation/config/testing/entities/testing.py +25 -0
  2. orionis/metadata/framework.py +1 -1
  3. orionis/services/asynchrony/{async_io.py → coroutines.py} +2 -1
  4. orionis/services/asynchrony/exceptions/__init__.py +0 -0
  5. orionis/services/asynchrony/exceptions/coroutine_exception.py +26 -0
  6. orionis/services/environment/dot_env.py +7 -7
  7. orionis/services/environment/env.py +56 -8
  8. orionis/services/environment/exceptions/__init__.py +0 -0
  9. orionis/services/environment/exceptions/value_exception.py +27 -0
  10. orionis/services/introspection/exceptions/__init__.py +0 -0
  11. orionis/services/introspection/exceptions/types.py +0 -0
  12. orionis/services/introspection/helpers/__init__.py +0 -0
  13. orionis/services/introspection/helpers/functions.py +285 -0
  14. orionis/services/introspection/reflection.py +216 -0
  15. orionis/services/parsers/exceptions/__init__.py +0 -0
  16. orionis/services/parsers/serializer.py +1 -1
  17. orionis/services/paths/exceptions/__init__.py +0 -0
  18. orionis/services/paths/exceptions/not_found_exceptions.py +28 -0
  19. orionis/services/paths/exceptions/path_value_exceptions.py +28 -0
  20. orionis/services/paths/resolver.py +6 -4
  21. orionis/services/standard/exceptions/__init__.py +0 -0
  22. orionis/services/standard/exceptions/path_value_exceptions.py +28 -0
  23. orionis/services/standard/std.py +4 -3
  24. orionis/test/entities/test_result.py +14 -1
  25. orionis/test/exceptions/test_persistence_error.py +34 -0
  26. orionis/test/exceptions/test_runtime_error.py +26 -0
  27. orionis/test/exceptions/test_value_error.py +26 -0
  28. orionis/test/logs/contracts/history.py +29 -56
  29. orionis/test/logs/history.py +309 -188
  30. orionis/test/output/contracts/dumper.py +24 -8
  31. orionis/test/output/dumper.py +52 -21
  32. orionis/test/suites/contracts/test_suite.py +27 -13
  33. orionis/test/suites/contracts/test_unit.py +101 -61
  34. orionis/test/suites/test_suite.py +45 -24
  35. orionis/test/suites/test_unit.py +559 -290
  36. orionis/unittesting.py +8 -0
  37. {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/METADATA +1 -1
  38. {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/RECORD +44 -26
  39. tests/services/asynchrony/test_async_io.py +3 -2
  40. /orionis/services/parsers/{exception.py → exceptions/exception_parser.py} +0 -0
  41. {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/WHEEL +0 -0
  42. {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/licenses/LICENCE +0 -0
  43. {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/top_level.txt +0 -0
  44. {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/zip-safe +0 -0
@@ -1,56 +1,117 @@
1
+ import inspect
1
2
  import io
3
+ import json
4
+ import os
2
5
  import re
3
6
  import time
4
- import inspect
5
7
  import traceback
6
8
  import unittest
7
- from pathlib import Path
9
+ from concurrent.futures import ThreadPoolExecutor, as_completed
10
+ from contextlib import redirect_stdout, redirect_stderr
8
11
  from datetime import datetime
12
+ from pathlib import Path
9
13
  from typing import Any, Dict, List, Optional, Tuple
10
- from contextlib import redirect_stdout, redirect_stderr
11
- from concurrent.futures import ThreadPoolExecutor, as_completed
12
14
  from rich.console import Console as RichConsole
15
+ from rich.live import Live
13
16
  from rich.panel import Panel
14
17
  from rich.syntax import Syntax
15
18
  from rich.table import Table
16
19
  from orionis.console.output.console import Console
17
- from orionis.test.logs.history import TestHistory
18
- from orionis.test.suites.contracts.test_unit import IUnitTest
19
20
  from orionis.test.entities.test_result import TestResult
20
21
  from orionis.test.enums.test_mode import ExecutionMode
21
22
  from orionis.test.enums.test_status import TestStatus
23
+ from orionis.test.exceptions.test_persistence_error import OrionisTestPersistenceError
22
24
  from orionis.test.exceptions.test_failure_exception import OrionisTestFailureException
23
- from rich.live import Live
24
- import os
25
+ from orionis.test.exceptions.test_value_error import OrionisTestValueError
26
+ from orionis.test.logs.history import TestHistory
27
+ from orionis.test.suites.contracts.test_unit import IUnitTest
25
28
 
26
29
  class UnitTest(IUnitTest):
27
30
  """
28
- UnitTest is a comprehensive testing utility class designed to facilitate the discovery, configuration,
29
- and execution of unit tests. It provides features for sequential and parallel test execution,
30
- customizable verbosity, fail-fast behavior, and rich output formatting using the `rich` library.
31
- loader (unittest.TestLoader): The test loader used to discover and load tests.
32
- suite (unittest.TestSuite): The test suite containing the discovered tests.
31
+ UnitTest is a comprehensive testing utility class for discovering, configuring, and executing unit tests.
32
+
33
+ This class supports both sequential and parallel test execution, customizable verbosity, fail-fast behavior,
34
+ and rich output formatting using the `rich` library.
35
+
36
+ Attributes
37
+ ----------
38
+ loader : unittest.TestLoader
39
+ The test loader used to discover and load tests.
40
+ suite : unittest.TestSuite
41
+ The test suite containing the discovered tests.
42
+ test_results : list of TestResult
43
+ A list to store the results of executed tests.
44
+ start_time : float
45
+ The start time of the test execution.
46
+ print_result : bool
47
+ Flag to determine whether to print test results.
48
+ verbosity : int
49
+ The verbosity level for test output.
50
+ execution_mode : str
51
+ The mode of test execution (e.g., 'SEQUENTIAL' or 'PARALLEL').
52
+ max_workers : int
53
+ The maximum number of workers for parallel execution.
54
+ fail_fast : bool
55
+ Flag to stop execution on the first failure.
56
+ rich_console : RichConsole
57
+ Console for rich text output.
58
+ orionis_console : Console
59
+ Console for standard output.
60
+ discovered_tests : list
61
+ A list to store discovered test cases.
62
+ width_output_component : int
63
+ The width of the table for displaying results.
64
+ throw_exception : bool
65
+ Flag to determine whether to throw exceptions on test failures.
66
+ persistent : bool
67
+ Flag to determine whether to persist test results in a database.
68
+ base_path : str
69
+ The base directory for test discovery and persistence.
33
70
  """
34
71
 
35
72
  def __init__(self) -> None:
36
73
  """
37
- Initializes the test unit with default configurations.
38
-
39
- Attributes:
40
- loader (unittest.TestLoader): The test loader used to discover tests.
41
- suite (unittest.TestSuite): The test suite to hold the discovered tests.
42
- test_results (List[TestResult]): A list to store the results of executed tests.
43
- start_time (float): The start time of the test execution.
44
- print_result (bool): Flag to determine whether to print test results.
45
- verbosity (int): The verbosity level for test output.
46
- execution_mode (str): The mode of test execution (e.g., SEQUENTIAL or PARALLEL).
47
- max_workers (int): The maximum number of workers for parallel execution.
48
- fail_fast (bool): Flag to stop execution on the first failure.
49
- rich_console (RichConsole): Console for rich text output.
50
- orionis_console (Console): Console for standard output.
51
- discovered_tests (List): A list to store discovered test cases.
52
- width_table (int): The width of the table for displaying results.
53
- throw_exception (bool): Flag to determine whether to throw exceptions on test failures.
74
+ Initialize the UnitTest instance with default configurations.
75
+
76
+ Parameters
77
+ ----------
78
+ self : UnitTest
79
+ The instance of the UnitTest class.
80
+
81
+ Attributes
82
+ ----------
83
+ loader : unittest.TestLoader
84
+ The test loader used to discover tests.
85
+ suite : unittest.TestSuite
86
+ The test suite to hold the discovered tests.
87
+ test_results : list of TestResult
88
+ A list to store the results of executed tests.
89
+ start_time : float
90
+ The start time of the test execution.
91
+ print_result : bool
92
+ Flag to determine whether to print test results.
93
+ verbosity : int
94
+ The verbosity level for test output.
95
+ execution_mode : str
96
+ The mode of test execution (e.g., 'SEQUENTIAL' or 'PARALLEL').
97
+ max_workers : int
98
+ The maximum number of workers for parallel execution.
99
+ fail_fast : bool
100
+ Flag to stop execution on the first failure.
101
+ rich_console : RichConsole
102
+ Console for rich text output.
103
+ orionis_console : Console
104
+ Console for standard output.
105
+ discovered_tests : list
106
+ A list to store discovered test cases.
107
+ width_output_component : int
108
+ The width of the table for displaying results.
109
+ throw_exception : bool
110
+ Flag to determine whether to throw exceptions on test failures.
111
+ persistent : bool
112
+ Flag to determine whether to persist test results in a database.
113
+ base_path : str
114
+ The base directory for test discovery and persistence.
54
115
  """
55
116
  self.loader = unittest.TestLoader()
56
117
  self.suite = unittest.TestSuite()
@@ -67,6 +128,7 @@ class UnitTest(IUnitTest):
67
128
  self.width_output_component: int = int(self.rich_console.width * 0.75)
68
129
  self.throw_exception: bool = False
69
130
  self.persistent: bool = False
131
+ self.persistent_driver: str = 'sqlite'
70
132
  self.base_path: str = "tests"
71
133
 
72
134
  def configure(
@@ -77,22 +139,35 @@ class UnitTest(IUnitTest):
77
139
  fail_fast: bool = None,
78
140
  print_result: bool = None,
79
141
  throw_exception: bool = False,
80
- persistent: bool = False
142
+ persistent: bool = False,
143
+ persistent_driver: str = 'sqlite'
81
144
  ) -> 'UnitTest':
82
145
  """
83
146
  Configures the UnitTest instance with the specified parameters.
84
147
 
85
- Parameters:
86
- verbosity (int, optional): The verbosity level for test output. Defaults to None.
87
- execution_mode (ExecutionMode, optional): The mode in which the tests will be executed. Defaults to None.
88
- max_workers (int, optional): The maximum number of workers to use for parallel execution. Defaults to None.
89
- fail_fast (bool, optional): Whether to stop execution upon the first failure. Defaults to None.
90
- print_result (bool, optional): Whether to print the test results after execution. Defaults to None.
91
- throw_exception (bool, optional): Whether to throw an exception if any test fails. Defaults to False.
92
- persistent (bool, optional): Whether to persist the test results in a database. Defaults to False.
93
-
94
- Returns:
95
- UnitTest: The configured UnitTest instance.
148
+ Parameters
149
+ ----------
150
+ verbosity : int, optional
151
+ The verbosity level for test output. If None, the current setting is retained.
152
+ execution_mode : str or ExecutionMode, optional
153
+ The mode in which the tests will be executed ('SEQUENTIAL' or 'PARALLEL'). If None, the current setting is retained.
154
+ max_workers : int, optional
155
+ The maximum number of workers to use for parallel execution. If None, the current setting is retained.
156
+ fail_fast : bool, optional
157
+ Whether to stop execution upon the first failure. If None, the current setting is retained.
158
+ print_result : bool, optional
159
+ Whether to print the test results after execution. If None, the current setting is retained.
160
+ throw_exception : bool, optional
161
+ Whether to throw an exception if any test fails. Defaults to False.
162
+ persistent : bool, optional
163
+ Whether to persist the test results in a database. Defaults to False.
164
+ persistent_driver : str, optional
165
+ The driver to use for persistent storage. Defaults to 'sqlite'.
166
+
167
+ Returns
168
+ -------
169
+ UnitTest
170
+ The configured UnitTest instance.
96
171
  """
97
172
  if verbosity is not None:
98
173
  self.verbosity = verbosity
@@ -117,6 +192,9 @@ class UnitTest(IUnitTest):
117
192
  if persistent is not None:
118
193
  self.persistent = persistent
119
194
 
195
+ if persistent_driver is not None:
196
+ self.persistent_driver = persistent_driver
197
+
120
198
  return self
121
199
 
122
200
  def discoverTestsInFolder(
@@ -128,24 +206,39 @@ class UnitTest(IUnitTest):
128
206
  tags: Optional[List[str]] = None
129
207
  ) -> 'UnitTest':
130
208
  """
131
- Discovers and loads unit tests from a specified folder.
132
- Args:
133
- folder_path (str): The relative path to the folder containing the tests.
134
- base_path (str, optional): The base directory where the test folder is located. Defaults to "tests".
135
- pattern (str, optional): The filename pattern to match test files. Defaults to "test_*.py".
136
- test_name_pattern (Optional[str], optional): A pattern to filter test names. Defaults to None.
137
- tags (Optional[List[str]], optional): A list of tags to filter tests. Defaults to None.
138
- Returns:
139
- UnitTest: The current instance of the UnitTest class with the discovered tests added.
140
- Raises:
141
- ValueError: If the test folder does not exist, no tests are found, or an error occurs during test discovery.
209
+ Parameters
210
+ ----------
211
+ folder_path : str
212
+ The relative path to the folder containing the tests.
213
+ base_path : str, optional
214
+ The base directory where the test folder is located. Defaults to "tests".
215
+ pattern : str, optional
216
+ The filename pattern to match test files. Defaults to "test_*.py".
217
+ test_name_pattern : str or None, optional
218
+ A pattern to filter test names. Defaults to None.
219
+ tags : list of str or None, optional
220
+ A list of tags to filter tests. Defaults to None.
221
+
222
+ Returns
223
+ -------
224
+ UnitTest
225
+ The current instance of the UnitTest class with the discovered tests added.
226
+
227
+ Raises
228
+ ------
229
+ OrionisTestValueError
230
+ If the test folder does not exist, no tests are found, or an error occurs during test discovery.
231
+
232
+ Notes
233
+ -----
234
+ This method updates the internal test suite with the discovered tests and tracks the number of tests found.
142
235
  """
143
236
  try:
144
237
  self.base_path = base_path
145
238
 
146
239
  full_path = Path(base_path) / folder_path
147
240
  if not full_path.exists():
148
- raise ValueError(f"Test folder not found: {full_path}")
241
+ raise OrionisTestValueError(f"Test folder not found: {full_path}")
149
242
 
150
243
  tests = self.loader.discover(
151
244
  start_dir=str(full_path),
@@ -160,7 +253,7 @@ class UnitTest(IUnitTest):
160
253
  tests = self._filterTestsByTags(tests, tags)
161
254
 
162
255
  if not list(tests):
163
- raise ValueError(f"No tests found in '{full_path}' matching pattern '{pattern}'")
256
+ raise OrionisTestValueError(f"No tests found in '{full_path}' matching pattern '{pattern}'")
164
257
 
165
258
  self.suite.addTests(tests)
166
259
 
@@ -173,22 +266,30 @@ class UnitTest(IUnitTest):
173
266
  return self
174
267
 
175
268
  except ImportError as e:
176
- raise ValueError(f"Error importing tests from '{full_path}': {str(e)}")
269
+ raise OrionisTestValueError(f"Error importing tests from '{full_path}': {str(e)}")
177
270
  except Exception as e:
178
- raise ValueError(f"Unexpected error discovering tests: {str(e)}")
271
+ raise OrionisTestValueError(f"Unexpected error discovering tests: {str(e)}")
179
272
 
180
273
  def discoverTestsInModule(self, module_name: str, test_name_pattern: Optional[str] = None) -> 'UnitTest':
181
274
  """
182
- Discovers and loads tests from a specified module, optionally filtering them
183
- by a test name pattern, and adds them to the test suite.
184
- Args:
185
- module_name (str): The name of the module to discover tests from.
186
- test_name_pattern (Optional[str]): A pattern to filter test names. Only
187
- tests matching this pattern will be included. Defaults to None.
188
- Returns:
189
- UnitTest: The current instance of the UnitTest class, allowing method chaining.
190
- Raises:
191
- ValueError: If the specified module cannot be imported.
275
+ Discovers and loads tests from a specified module, optionally filtering by a test name pattern, and adds them to the test suite.
276
+
277
+ Parameters
278
+ ----------
279
+ module_name : str
280
+ Name of the module from which to discover tests.
281
+ test_name_pattern : str, optional
282
+ Pattern to filter test names. Only tests matching this pattern will be included. Defaults to None.
283
+
284
+ Returns
285
+ -------
286
+ UnitTest
287
+ The current instance of the UnitTest class, allowing method chaining.
288
+
289
+ Exceptions
290
+ ----------
291
+ OrionisTestValueError
292
+ If the specified module cannot be imported.
192
293
  """
193
294
  try:
194
295
 
@@ -207,24 +308,39 @@ class UnitTest(IUnitTest):
207
308
 
208
309
  return self
209
310
  except ImportError as e:
210
- raise ValueError(f"Error importing module '{module_name}': {str(e)}")
311
+ raise OrionisTestValueError(f"Error importing module '{module_name}': {str(e)}")
211
312
 
212
313
  def _startMessage(self) -> None:
213
314
  """
214
- Displays a formatted message indicating the start of the test suite execution.
215
- This method prints details about the test suite, including the total number of tests,
315
+ Prints a formatted message indicating the start of the test suite execution.
316
+
317
+ Parameters
318
+ ----------
319
+ self : UnitTest
320
+ The instance of the UnitTest class.
321
+
322
+ Notes
323
+ -----
324
+ This method displays details about the test suite, including the total number of tests,
216
325
  the execution mode (parallel or sequential), and the start time. The message is styled
217
326
  and displayed using the `rich` library.
218
- Attributes:
219
- print_result (bool): Determines whether the message should be printed.
220
- suite (TestSuite): The test suite containing the tests to be executed.
221
- max_workers (int): The number of workers used in parallel execution mode.
222
- execution_mode (ExecutionMode): The mode of execution (parallel or sequential).
223
- orionis_console (Console): The console object for handling standard output.
224
- rich_console (Console): The rich console object for styled output.
225
- width_table (int): The calculated width of the message panel for formatting.
226
- Raises:
227
- AttributeError: If required attributes are not set before calling this method.
327
+
328
+ Attributes Used
329
+ --------------
330
+ print_result : bool
331
+ Determines whether the message should be printed.
332
+ suite : unittest.TestSuite
333
+ The test suite containing the tests to be executed.
334
+ max_workers : int
335
+ The number of workers used in parallel execution mode.
336
+ execution_mode : str
337
+ The mode of execution ('SEQUENTIAL' or 'PARALLEL').
338
+ orionis_console : Console
339
+ The console object for handling standard output.
340
+ rich_console : RichConsole
341
+ The rich console object for styled output.
342
+ width_output_component : int
343
+ The calculated width of the message panel for formatting.
228
344
  """
229
345
  if self.print_result:
230
346
  test_count = len(list(self._flattenTestSuite(self.suite)))
@@ -238,7 +354,7 @@ class UnitTest(IUnitTest):
238
354
  self.orionis_console.newLine()
239
355
  self.rich_console.print(
240
356
  Panel(
241
- '\n'.join(textlines),
357
+ str('\n').join(textlines),
242
358
  border_style="blue",
243
359
  title="🧪 Orionis Framework - Component Test Suite",
244
360
  title_align="center",
@@ -251,17 +367,23 @@ class UnitTest(IUnitTest):
251
367
  def run(self, print_result: bool = None, throw_exception: bool = None) -> Dict[str, Any]:
252
368
  """
253
369
  Executes the test suite and processes the results.
254
- Args:
255
- print_result (bool, optional): If provided, overrides the instance's
256
- `print_result` attribute to determine whether to print the test results.
257
- throw_exception (bool, optional): If True, raises an exception if any
258
- test failures or errors are detected.
259
- Returns:
260
- Dict[str, Any]: A summary of the test execution, including details such as
261
- execution time, test results, and a timestamp.
262
- Raises:
263
- OrionisTestFailureException: If `throw_exception` is True and there are
264
- test failures or errors.
370
+
371
+ Parameters
372
+ ----------
373
+ print_result : bool, optional
374
+ If provided, overrides the instance's `print_result` attribute to determine whether to print results.
375
+ throw_exception : bool, optional
376
+ If True, raises an exception if any test failures or errors are detected.
377
+
378
+ Returns
379
+ -------
380
+ dict
381
+ A summary of the test execution, including details such as execution time, results, and timestamp.
382
+
383
+ Raises
384
+ ------
385
+ OrionisTestFailureException
386
+ If `throw_exception` is True and there are test failures or errors.
265
387
  """
266
388
  if print_result is not None:
267
389
  self.print_result = print_result
@@ -300,22 +422,30 @@ class UnitTest(IUnitTest):
300
422
 
301
423
  # Print captured output
302
424
  if self.print_result:
303
- self._displayResults(summary, result)
425
+ self._displayResults(summary)
304
426
 
305
427
  # Print Execution Time
306
428
  if not result.wasSuccessful() and self.throw_exception:
307
429
  raise OrionisTestFailureException(result)
308
430
 
431
+ # Return the summary of the test results
309
432
  return summary
310
433
 
311
434
  def _runTestsSequentially(self, output_buffer: io.StringIO, error_buffer: io.StringIO) -> unittest.TestResult:
312
435
  """
313
436
  Executes the test suite sequentially, capturing the output and error streams.
314
- Args:
315
- output_buffer (io.StringIO): A buffer to capture the standard output during test execution.
316
- error_buffer (io.StringIO): A buffer to capture the standard error during test execution.
317
- Returns:
318
- unittest.TestResult: The result of the test suite execution, containing information about
437
+
438
+ Parameters
439
+ ----------
440
+ output_buffer : io.StringIO
441
+ A buffer to capture the standard output during test execution.
442
+ error_buffer : io.StringIO
443
+ A buffer to capture the standard error during test execution.
444
+
445
+ Returns
446
+ -------
447
+ unittest.TestResult
448
+ The result of the test suite execution, containing information about
319
449
  passed, failed, and skipped tests.
320
450
  """
321
451
  with redirect_stdout(output_buffer), redirect_stderr(error_buffer):
@@ -331,32 +461,41 @@ class UnitTest(IUnitTest):
331
461
 
332
462
  def _runTestsInParallel(self, output_buffer: io.StringIO, error_buffer: io.StringIO) -> unittest.TestResult:
333
463
  """
334
- Execute tests in parallel using a thread pool.
335
- This method runs all test cases in the provided test suite concurrently,
336
- utilizing a thread pool for parallel execution. It collects and combines
337
- the results of all test cases into a single result object.
338
- Args:
339
- output_buffer (io.StringIO): A buffer to capture standard output during test execution.
340
- error_buffer (io.StringIO): A buffer to capture standard error during test execution.
341
- Returns:
342
- unittest.TestResult: A combined result object containing the outcomes of all executed tests.
343
- Notes:
344
- - The method uses a custom result class to aggregate test results.
345
- - If `fail_fast` is enabled and a test fails, the remaining tests are canceled.
346
- - Minimal output is produced for individual test runs during parallel execution.
347
- """
348
- """Execute tests in parallel with thread pooling."""
464
+ Runs all test cases in the provided test suite concurrently using a thread pool,
465
+ aggregating the results into a single result object. Standard output and error
466
+ are redirected to the provided buffers during execution.
467
+
468
+ Parameters
469
+ ----------
470
+ output_buffer : io.StringIO
471
+ Buffer to capture standard output during test execution.
472
+ error_buffer : io.StringIO
473
+ Buffer to capture standard error during test execution.
474
+
475
+ Returns
476
+ -------
477
+ unittest.TestResult
478
+ Combined result object containing the outcomes of all executed tests.
479
+
480
+ Notes
481
+ -----
482
+ - Uses a custom result class to aggregate test results.
483
+ - If `fail_fast` is enabled and a test fails, remaining tests are canceled.
484
+ """
485
+
486
+ # Flatten the test suite to get individual test cases
349
487
  test_cases = list(self._flattenTestSuite(self.suite))
350
488
 
351
489
  # Create a custom result instance to collect all results
352
490
  result_class = self._createCustomResultClass()
353
491
  combined_result = result_class(io.StringIO(), descriptions=True, verbosity=self.verbosity)
354
492
 
493
+ # Helper function to run a single test and return its result.
494
+ # Minimal output for parallel runs
355
495
  def run_single_test(test):
356
- """Helper function to run a single test and return its result."""
357
496
  runner = unittest.TextTestRunner(
358
497
  stream=io.StringIO(),
359
- verbosity=0, # Minimal output for parallel runs
498
+ verbosity=0,
360
499
  failfast=False,
361
500
  resultclass=result_class
362
501
  )
@@ -379,18 +518,23 @@ class UnitTest(IUnitTest):
379
518
 
380
519
  def _mergeTestResults(self, combined_result: unittest.TestResult, individual_result: unittest.TestResult) -> None:
381
520
  """
382
- Merges the results of two unittest.TestResult objects into a combined result.
383
- This method updates the combined_result object by adding the test run counts,
521
+ Merge the results of two unittest.TestResult objects.
522
+
523
+ This method updates the `combined_result` object by adding the test run counts,
384
524
  failures, errors, skipped tests, expected failures, and unexpected successes
385
- from the individual_result object. Additionally, it merges any custom test
386
- results stored in the 'test_results' attribute, if present.
387
- Args:
388
- combined_result (unittest.TestResult): The TestResult object to which the
389
- results will be merged.
390
- individual_result (unittest.TestResult): The TestResult object containing
391
- the results to be merged into the combined_result.
392
- Returns:
393
- None
525
+ from the `individual_result` object. Additionally, it merges any custom test
526
+ results stored in the `test_results` attribute, if present.
527
+
528
+ Parameters
529
+ ----------
530
+ combined_result : unittest.TestResult
531
+ The TestResult object to which the results will be merged.
532
+ individual_result : unittest.TestResult
533
+ The TestResult object containing the results to be merged into the combined_result.
534
+
535
+ Returns
536
+ -------
537
+ None
394
538
  """
395
539
  combined_result.testsRun += individual_result.testsRun
396
540
  combined_result.failures.extend(individual_result.failures)
@@ -407,25 +551,30 @@ class UnitTest(IUnitTest):
407
551
 
408
552
  def _createCustomResultClass(self) -> type:
409
553
  """
410
- Creates a custom test result class that extends `unittest.TextTestResult` to provide enhanced
411
- functionality for tracking test execution details, including timings, statuses, and error information.
412
- Returns:
413
- type: A dynamically created class `EnhancedTestResult` that overrides methods to handle
414
- test results, including success, failure, error, and skipped tests. The class collects
415
- detailed information about each test, such as execution time, error messages, traceback,
416
- and file path.
417
- The `EnhancedTestResult` class includes:
418
- - `startTest`: Records the start time of a test.
419
- - `stopTest`: Calculates and stores the elapsed time for a test.
420
- - `addSuccess`: Logs details of a successful test.
421
- - `addFailure`: Logs details of a failed test, including error message and traceback.
422
- - `addError`: Logs details of a test that encountered an error, including error message and traceback.
423
- - `addSkip`: Logs details of a skipped test, including the reason for skipping.
424
- Note:
425
- This method uses the `this` reference to access the outer class's methods, such as `_extractErrorInfo`.
554
+ Creates a custom test result class for enhanced test tracking.
555
+ This method dynamically generates an `EnhancedTestResult` class that extends
556
+ `unittest.TextTestResult`. The custom class provides advanced functionality for
557
+ tracking test execution details, including timings, statuses, and error information.
558
+
559
+ Returns
560
+ -------
561
+ type
562
+ A dynamically created class `EnhancedTestResult` that overrides methods to handle
563
+ test results, including success, failure, error, and skipped tests. The class
564
+ collects detailed information about each test, such as execution time, error
565
+ messages, traceback, and file path.
566
+
567
+ Notes
568
+ -----
569
+ The `EnhancedTestResult` class includes the following method overrides:
570
+ The method uses the `this` reference to access the outer class's methods, such as
571
+ `_extractErrorInfo`, for extracting and formatting error information.
426
572
  """
573
+
574
+ # Use `this` to refer to the outer class instance
427
575
  this = self
428
576
 
577
+ # Define the custom test result class
429
578
  class EnhancedTestResult(unittest.TextTestResult):
430
579
  def __init__(self, *args, **kwargs):
431
580
  super().__init__(*args, **kwargs)
@@ -519,33 +668,58 @@ class UnitTest(IUnitTest):
519
668
  )
520
669
  )
521
670
 
671
+ # Return the dynamically created EnhancedTestResult class
522
672
  return EnhancedTestResult
523
673
 
524
674
  def _generateSummary(self, result: unittest.TestResult, execution_time: float) -> Dict[str, Any]:
525
675
  """
526
- Generates a summary of the test results, including details about each test,
527
- performance data, and overall statistics.
528
- Args:
529
- result (unittest.TestResult): The result object containing details of the test execution.
530
- execution_time (float): The total execution time of the test suite in seconds.
531
- Returns:
532
- Dict[str, Any]: A dictionary containing the following keys:
533
- - "total_tests" (int): The total number of tests executed.
534
- - "passed" (int): The number of tests that passed.
535
- - "failed" (int): The number of tests that failed.
536
- - "errors" (int): The number of tests that encountered errors.
537
- - "skipped" (int): The number of tests that were skipped.
538
- - "total_time" (float): The total execution time of the test suite.
539
- - "success_rate" (float): The percentage of tests that passed.
540
- - "test_details" (List[Dict[str, Any]]): A list of dictionaries containing details about each test:
541
- - "id" (str): The unique identifier of the test.
542
- - "class" (str): The class name of the test.
543
- - "method" (str): The method name of the test.
544
- - "status" (str): The status of the test (e.g., "PASSED", "FAILED").
545
- - "execution_time" (float): The execution time of the test in seconds.
546
- - "error_message" (str): The error message if the test failed or errored.
547
- - "traceback" (str): The traceback information if the test failed or errored.
548
- - "file_path" (str): The file path of the test.
676
+ Generate a summary of the test results, including statistics and details for each test.
677
+
678
+ Parameters
679
+ ----------
680
+ result : unittest.TestResult
681
+ The result object containing details of the test execution.
682
+ execution_time : float
683
+ The total execution time of the test suite in seconds.
684
+
685
+ Returns
686
+ -------
687
+ Dict[str, Any]
688
+ A dictionary containing the following keys:
689
+ total_tests : int
690
+ The total number of tests executed.
691
+ passed : int
692
+ The number of tests that passed.
693
+ failed : int
694
+ The number of tests that failed.
695
+ errors : int
696
+ The number of tests that encountered errors.
697
+ skipped : int
698
+ The number of tests that were skipped.
699
+ total_time : float
700
+ The total execution time of the test suite.
701
+ success_rate : float
702
+ The percentage of tests that passed.
703
+ test_details : List[Dict[str, Any]]
704
+ A list of dictionaries with details for each test, including:
705
+ id : str
706
+ The unique identifier of the test.
707
+ class : str
708
+ The class name of the test.
709
+ method : str
710
+ The method name of the test.
711
+ status : str
712
+ The status of the test (e.g., "PASSED", "FAILED").
713
+ execution_time : float
714
+ The execution time of the test in seconds.
715
+ error_message : str
716
+ The error message if the test failed or errored.
717
+ traceback : str
718
+ The traceback information if the test failed or errored.
719
+ file_path : str
720
+ The file path of the test.
721
+ doc_string : str
722
+ The docstring of the test method, if available.
549
723
  """
550
724
  test_details = []
551
725
 
@@ -597,45 +771,91 @@ class UnitTest(IUnitTest):
597
771
 
598
772
  def _persistTestResults(self, summary: Dict[str, Any]) -> None:
599
773
  """
600
- Persists the test results in a SQLite database.
601
- Args:
602
- summary (Dict[str, Any]): A dictionary containing the test summary data.
603
- Expected keys in the dictionary:
604
- - "total_tests" (int): Total number of tests executed.
605
- - "passed" (int): Number of tests that passed.
606
- - "failed" (int): Number of tests that failed.
607
- - "errors" (int): Number of tests that encountered errors.
608
- - "skipped" (int): Number of tests that were skipped.
609
- - "total_time" (float): Total duration of the test run in seconds.
610
- - "success_rate" (float): Percentage of tests that passed.
611
- Returns:
612
- None
613
- """
614
- full_path = os.path.abspath(os.path.join(os.getcwd(), self.base_path))
615
- log = TestHistory(full_path)
774
+ Persist the test results summary using the configured persistent driver.
775
+
776
+ Parameters
777
+ ----------
778
+ summary : dict
779
+ The summary of test results to persist.
780
+
781
+ Notes
782
+ -----
783
+ Depending on the value of `self.persistent_driver`, the summary is either:
784
+ - Stored in an SQLite database (using the TestHistory class), or
785
+ - Written to a timestamped JSON file in the specified base path.
786
+
787
+ Raises
788
+ ------
789
+ OSError
790
+ If there is an error creating directories or writing files.
791
+ Exception
792
+ If database operations fail.
793
+ """
794
+
616
795
  try:
617
- log.createTableIfNotExists()
618
- log.insertReport(summary)
619
- finally:
620
- log.close()
796
+ if self.persistent_driver == 'sqlite':
797
+
798
+ # Determine the absolute path for storing results
799
+ project = os.getcwd().split(os.sep)[-1]
800
+ storage_path = None
801
+ if project in ['framework', 'orionis']:
802
+ storage_path = os.path.abspath(os.path.join(os.getcwd(), self.base_path))
803
+
804
+ # Initialize the TestHistory class for database operations
805
+ history = TestHistory(
806
+ storage_path=storage_path,
807
+ db_name='tests.sqlite',
808
+ table_name='reports'
809
+ )
810
+
811
+ # Insert the summary into the database
812
+ history.create(summary)
813
+
814
+ elif self.persistent_driver == 'json':
815
+
816
+ # Get the current timestamp for the log file name
817
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
818
+
819
+ # Ensure the base path exists and write the summary to a JSON file
820
+ os.makedirs(self.base_path, exist_ok=True)
821
+
822
+ # Create the log file path with the timestamp
823
+ log_path = os.path.join(self.base_path, f'test_{timestamp}.json')
824
+
825
+ # Write the summary to the JSON file
826
+ with open(log_path, 'w', encoding='utf-8') as log:
827
+ json.dump(summary, log, indent=4)
828
+ except OSError as e:
829
+ raise OSError(f"Error creating directories or writing files: {str(e)}")
830
+ except Exception as e:
831
+ raise OrionisTestPersistenceError(f"Error persisting test results: {str(e)}")
621
832
 
622
833
  def _printSummaryTable(self, summary: Dict[str, Any]) -> None:
623
834
  """
624
835
  Prints a summary table of test results using the Rich library.
625
836
 
626
- Args:
627
- summary (Dict[str, Any]): A dictionary containing the test summary data.
628
- Expected keys in the dictionary:
629
- - "total_tests" (int): Total number of tests executed.
630
- - "passed" (int): Number of tests that passed.
631
- - "failed" (int): Number of tests that failed.
632
- - "errors" (int): Number of tests that encountered errors.
633
- - "skipped" (int): Number of tests that were skipped.
634
- - "total_time" (float): Total duration of the test run in seconds.
635
- - "success_rate" (float): Percentage of tests that passed.
636
-
637
- Returns:
638
- None
837
+ Parameters
838
+ ----------
839
+ summary : dict
840
+ Dictionary with the test summary data. Must contain the following keys:
841
+ total_tests : int
842
+ Total number of tests executed.
843
+ passed : int
844
+ Number of tests that passed.
845
+ failed : int
846
+ Number of tests that failed.
847
+ errors : int
848
+ Number of tests that had errors.
849
+ skipped : int
850
+ Number of tests that were skipped.
851
+ total_time : float
852
+ Total duration of the test execution in seconds.
853
+ success_rate : float
854
+ Percentage of tests that passed.
855
+
856
+ Returns
857
+ -------
858
+ None
639
859
  """
640
860
  table = Table(
641
861
  show_header=True,
@@ -664,23 +884,29 @@ class UnitTest(IUnitTest):
664
884
 
665
885
  def _filterTestsByName(self, suite: unittest.TestSuite, pattern: str) -> unittest.TestSuite:
666
886
  """
667
- Filters the tests in a given test suite based on a specified name pattern.
668
- Args:
669
- suite (unittest.TestSuite): The test suite containing the tests to filter.
670
- pattern (str): A regular expression pattern to match test names.
671
- Returns:
672
- unittest.TestSuite: A new test suite containing only the tests that match the pattern.
673
- Raises:
674
- ValueError: If the provided pattern is not a valid regular expression.
675
- Notes:
676
- - The method flattens the input test suite to iterate over individual tests.
677
- - A test is included in the filtered suite if its ID matches the provided regex pattern.
887
+ Filters tests in a given test suite based on a specified name pattern.
888
+ Parameters
889
+ ----------
890
+ suite : unittest.TestSuite
891
+ The test suite containing the tests to filter.
892
+ pattern : str
893
+ A regular expression pattern to match test names.
894
+ Returns
895
+ -------
896
+ unittest.TestSuite
897
+ A new test suite containing only the tests that match the pattern.
898
+ Raises
899
+ ------
900
+ OrionisTestValueError
901
+ If the provided pattern is not a valid regular expression.
902
+ Notes
903
+ -----
678
904
  """
679
905
  filtered_suite = unittest.TestSuite()
680
906
  try:
681
907
  regex = re.compile(pattern)
682
908
  except re.error as e:
683
- raise ValueError(f"Invalid test name pattern: {str(e)}")
909
+ raise OrionisTestValueError(f"Invalid test name pattern: {str(e)}")
684
910
 
685
911
  for test in self._flattenTestSuite(suite):
686
912
  if regex.search(test.id()):
@@ -690,22 +916,31 @@ class UnitTest(IUnitTest):
690
916
 
691
917
  def _filterTestsByTags(self, suite: unittest.TestSuite, tags: List[str]) -> unittest.TestSuite:
692
918
  """
693
- Filters a unittest TestSuite to include only tests that match the specified tags.
694
- This method iterates through all tests in the provided TestSuite and checks
695
- for a `__tags__` attribute either on the test method or the test case class.
696
- If any of the specified tags match the tags associated with the test, the test
697
- is added to the filtered TestSuite.
698
- Args:
699
- suite (unittest.TestSuite): The original TestSuite containing all tests.
700
- tags (List[str]): A list of tags to filter the tests by.
701
- Returns:
702
- unittest.TestSuite: A new TestSuite containing only the tests that match
703
- the specified tags.
919
+ Filter tests in a unittest TestSuite by specified tags.
920
+
921
+ Iterates through all tests in the provided TestSuite and checks for a `__tags__`
922
+ attribute either on the test method or the test case class. If any of the specified
923
+ tags match the tags associated with the test, the test is included in the filtered suite.
924
+
925
+ Parameters
926
+ ----------
927
+ suite : unittest.TestSuite
928
+ The original TestSuite containing all tests.
929
+ tags : list of str
930
+ List of tags to filter the tests by.
931
+
932
+ Returns
933
+ -------
934
+ unittest.TestSuite
935
+ A new TestSuite containing only the tests that match the specified tags.
704
936
  """
937
+
938
+ # Initialize an empty TestSuite to hold the filtered tests
705
939
  filtered_suite = unittest.TestSuite()
706
940
  tag_set = set(tags)
707
941
 
708
942
  for test in self._flattenTestSuite(suite):
943
+
709
944
  # Get test method if this is a TestCase instance
710
945
  test_method = getattr(test, test._testMethodName, None)
711
946
 
@@ -714,23 +949,34 @@ class UnitTest(IUnitTest):
714
949
  method_tags = set(getattr(test_method, '__tags__'))
715
950
  if tag_set.intersection(method_tags):
716
951
  filtered_suite.addTest(test)
952
+
717
953
  # Also check on the test case class
718
954
  elif hasattr(test, '__tags__'):
719
955
  class_tags = set(getattr(test, '__tags__'))
720
956
  if tag_set.intersection(class_tags):
721
957
  filtered_suite.addTest(test)
722
958
 
959
+ # Return the filtered suite containing only tests with matching tags
723
960
  return filtered_suite
724
961
 
725
962
  def _flattenTestSuite(self, suite: unittest.TestSuite) -> List[unittest.TestCase]:
726
963
  """
727
- Flattens a nested unittest.TestSuite into a list of individual unittest.TestCase instances.
728
- This method recursively traverses the given TestSuite, extracting all TestCase instances
729
- while avoiding duplicates. It ensures that each TestCase appears only once in the resulting list.
730
- Args:
731
- suite (unittest.TestSuite): The TestSuite to be flattened.
732
- Returns:
733
- List[unittest.TestCase]: A list of unique TestCase instances extracted from the TestSuite.
964
+ Recursively flattens a nested unittest.TestSuite into a list of unique unittest.TestCase instances.
965
+
966
+ Parameters
967
+ ----------
968
+ suite : unittest.TestSuite
969
+ The test suite to flatten, which may contain nested suites or test cases.
970
+
971
+ Returns
972
+ -------
973
+ List[unittest.TestCase]
974
+ A list containing all unique TestCase instances extracted from the suite.
975
+
976
+ Notes
977
+ -----
978
+ This method traverses the given TestSuite recursively, collecting all TestCase instances
979
+ and ensuring that each test appears only once in the resulting list.
734
980
  """
735
981
  tests = []
736
982
  seen = set()
@@ -748,19 +994,25 @@ class UnitTest(IUnitTest):
748
994
 
749
995
  def _sanitizeTraceback(self, test_path: str, traceback_test: str) -> str:
750
996
  """
751
- Sanitizes a traceback string to extract and display the most relevant parts
997
+ Sanitize a traceback string to extract and display the most relevant parts
752
998
  related to a specific test file.
753
- Args:
754
- test_path (str): The file path of the test file being analyzed.
755
- traceback_test (str): The full traceback string to be sanitized.
756
- Returns:
757
- str: A sanitized traceback string containing only the relevant parts
758
- related to the test file. If no relevant parts are found, the full
759
- traceback is returned. If the traceback is empty, a default message
760
- "No traceback available" is returned.
999
+
1000
+ Parameters
1001
+ ----------
1002
+ test_path : str
1003
+ The file path of the test file being analyzed.
1004
+ traceback_test : str
1005
+ The full traceback string to be sanitized.
1006
+
1007
+ Returns
1008
+ -------
1009
+ str
1010
+ A sanitized traceback string containing only the relevant parts related to the test file.
1011
+ If no relevant parts are found, the full traceback is returned.
1012
+ If the traceback is empty, a default message "No traceback available for this test." is returned.
761
1013
  """
762
1014
  if not traceback_test:
763
- return "No traceback available"
1015
+ return "No traceback available for this test."
764
1016
 
765
1017
  # Try to extract the test file name
766
1018
  file_match = re.search(r'([^/\\]+)\.py', test_path)
@@ -787,26 +1039,32 @@ class UnitTest(IUnitTest):
787
1039
  if not relevant_lines:
788
1040
  return traceback_test
789
1041
 
790
- return '\n'.join(relevant_lines)
1042
+ # Remove any lines that are not relevant to the test file
1043
+ return str('\n').join(relevant_lines)
791
1044
 
792
- def _displayResults(self, summary: Dict[str, Any], result: unittest.TestResult) -> None:
1045
+ def _displayResults(self, summary: Dict[str, Any]) -> None:
793
1046
  """
794
- Displays the results of the test execution, including a summary table and detailed
1047
+ Display the results of the test execution, including a summary table and detailed
795
1048
  information about failed or errored tests grouped by their test classes.
796
- Args:
797
- summary (Dict[str, Any]): A dictionary containing the summary of the test execution,
798
- including test details, statuses, and execution times.
799
- result (unittest.TestResult): The result object containing information about the
800
- test run, including successes, failures, and errors.
801
- Behavior:
802
- - Prints a summary table of the test results.
803
- - Groups failed and errored tests by their test class and displays them in a
804
- structured format using panels.
805
- - For each failed or errored test, displays the traceback in a syntax-highlighted
806
- panel with additional metadata such as the test method name and execution time.
807
- - Uses different icons and border colors to distinguish between failed and errored tests.
808
- - Calls a finishing message method after displaying all results.
1049
+
1050
+ Parameters
1051
+ ----------
1052
+ summary : dict
1053
+ Dictionary containing the summary of the test execution, including test details,
1054
+ statuses, and execution times.
1055
+
1056
+ Notes
1057
+ -----
1058
+ - Prints a summary table of the test results.
1059
+ - Groups failed and errored tests by their test class and displays them in a structured
1060
+ format using panels.
1061
+ - For each failed or errored test, displays the traceback in a syntax-highlighted panel
1062
+ with additional metadata such as the test method name and execution time.
1063
+ - Uses different icons and border colors to distinguish between failed and errored tests.
1064
+ - Calls a finishing message method after displaying all results.
809
1065
  """
1066
+
1067
+ # Print summary table
810
1068
  self._printSummaryTable(summary)
811
1069
 
812
1070
  # Group failures and errors by test class
@@ -838,7 +1096,8 @@ class UnitTest(IUnitTest):
838
1096
  icon = "❌" if test["status"] == TestStatus.FAILED.name else "💥"
839
1097
  border_color = "yellow" if test["status"] == TestStatus.FAILED.name else "red"
840
1098
 
841
- if test['execution_time'] == 0:
1099
+ # Ensure execution time is never zero for display purposes
1100
+ if not test['execution_time'] or test['execution_time'] == 0:
842
1101
  test['execution_time'] = 0.001
843
1102
 
844
1103
  panel = Panel(
@@ -858,16 +1117,24 @@ class UnitTest(IUnitTest):
858
1117
 
859
1118
  def _extractErrorInfo(self, traceback_str: str) -> Tuple[Optional[str], Optional[str]]:
860
1119
  """
861
- Extracts error information from a traceback string.
862
- This method processes a traceback string to extract the file path of the
863
- Python file where the error occurred and cleans up the traceback by
864
- removing framework internals and irrelevant noise.
865
- Args:
866
- traceback_str (str): The traceback string to process.
867
- Returns:
868
- Tuple[Optional[str], Optional[str]]: A tuple containing:
869
- - The file path of the Python file where the error occurred, or None if not found.
870
- - The cleaned-up traceback string, or the original traceback string if no cleanup was performed.
1120
+ Extract error information from a traceback string.
1121
+ This method processes a traceback string to extract the file path of the Python file where the error occurred and
1122
+ cleans up the traceback by removing framework internals and irrelevant noise.
1123
+
1124
+ Parameters
1125
+ ----------
1126
+ traceback_str : str
1127
+ The traceback string to process.
1128
+
1129
+ Returns
1130
+ -------
1131
+ Tuple[Optional[str], Optional[str]]
1132
+ A tuple containing:
1133
+
1134
+ Notes
1135
+ -----
1136
+ Framework internals and lines containing 'unittest/', 'lib/python', or 'site-packages' are removed from the traceback.
1137
+ The cleaned traceback starts from the first occurrence of the test file path.
871
1138
  """
872
1139
  # Extract file path
873
1140
  file_matches = re.findall(r'File ["\'](.*?.py)["\']', traceback_str)
@@ -890,22 +1157,26 @@ class UnitTest(IUnitTest):
890
1157
  if relevant_lines_started:
891
1158
  clean_lines.append(line)
892
1159
 
893
- clean_tb = '\n'.join(clean_lines) if clean_lines else traceback_str
1160
+ clean_tb = str('\n').join(clean_lines) if clean_lines else traceback_str
894
1161
 
895
1162
  return file_path, clean_tb
896
1163
 
897
1164
  def _finishMessage(self, summary: Dict[str, Any]) -> None:
898
1165
  """
899
- Displays a summary message for the test suite execution if result printing is enabled.
900
- Args:
901
- summary (Dict[str, Any]): A dictionary containing the test suite summary,
902
- including keys such as 'failed', 'errors', and 'total_time'.
903
- Behavior:
904
- - If `self.print_result` is False, the method returns without displaying anything.
905
- - Constructs a message indicating the total execution time of the test suite.
906
- - Displays a status icon (✅ for success, ❌ for failure) based on the presence of
907
- failures or errors in the test suite.
908
- - Formats and prints the message within a styled panel using the `rich` library.
1166
+ Display a summary message for the test suite execution.
1167
+
1168
+ Parameters
1169
+ ----------
1170
+ summary : dict
1171
+ Dictionary containing the test suite summary, including keys such as
1172
+ 'failed', 'errors', and 'total_time'.
1173
+
1174
+ Notes
1175
+ -----
1176
+ - If `self.print_result` is False, the method returns without displaying anything.
1177
+ - Shows a status icon (✅ for success, ❌ for failure) based on the presence of
1178
+ failures or errors in the test suite.
1179
+ - Formats and prints the message within a styled panel using the `rich` library.
909
1180
  """
910
1181
  if not self.print_result:
911
1182
  return
@@ -926,32 +1197,30 @@ class UnitTest(IUnitTest):
926
1197
 
927
1198
  def getTestNames(self) -> List[str]:
928
1199
  """
929
- Retrieves a list of test names from the test suite.
1200
+ Get a list of test names (unique identifiers) from the test suite.
930
1201
 
931
- This method flattens the test suite and extracts the unique identifier
932
- (`id`) of each test case.
933
-
934
- Returns:
935
- List[str]: A list of test names (unique identifiers) from the test suite.
1202
+ Returns
1203
+ -------
1204
+ List[str]
1205
+ List of test names (unique identifiers) from the test suite.
936
1206
  """
937
1207
  return [test.id() for test in self._flattenTestSuite(self.suite)]
938
1208
 
939
1209
  def getTestCount(self) -> int:
940
1210
  """
941
- Calculate the total number of tests in the test suite.
942
-
943
- This method flattens the test suite structure and counts the total
944
- number of individual test cases.
1211
+ Returns the total number of test cases in the test suite.
945
1212
 
946
- Returns:
947
- int: The total number of test cases in the test suite.
1213
+ Returns
1214
+ -------
1215
+ int
1216
+ The total number of individual test cases in the suite.
948
1217
  """
949
1218
  return len(list(self._flattenTestSuite(self.suite)))
950
1219
 
951
1220
  def clearTests(self) -> None:
952
1221
  """
953
- Clears the current test suite by reinitializing it to an empty `unittest.TestSuite`.
1222
+ Clear all tests from the current test suite.
954
1223
 
955
- This method is used to reset the test suite, removing any previously added tests.
1224
+ Resets the internal test suite to an empty `unittest.TestSuite`, removing any previously added tests.
956
1225
  """
957
1226
  self.suite = unittest.TestSuite()