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.
- orionis/foundation/config/testing/entities/testing.py +25 -0
- orionis/metadata/framework.py +1 -1
- orionis/services/asynchrony/{async_io.py → coroutines.py} +2 -1
- orionis/services/asynchrony/exceptions/__init__.py +0 -0
- orionis/services/asynchrony/exceptions/coroutine_exception.py +26 -0
- orionis/services/environment/dot_env.py +7 -7
- orionis/services/environment/env.py +56 -8
- orionis/services/environment/exceptions/__init__.py +0 -0
- orionis/services/environment/exceptions/value_exception.py +27 -0
- orionis/services/introspection/exceptions/__init__.py +0 -0
- orionis/services/introspection/exceptions/types.py +0 -0
- orionis/services/introspection/helpers/__init__.py +0 -0
- orionis/services/introspection/helpers/functions.py +285 -0
- orionis/services/introspection/reflection.py +216 -0
- orionis/services/parsers/exceptions/__init__.py +0 -0
- orionis/services/parsers/serializer.py +1 -1
- orionis/services/paths/exceptions/__init__.py +0 -0
- orionis/services/paths/exceptions/not_found_exceptions.py +28 -0
- orionis/services/paths/exceptions/path_value_exceptions.py +28 -0
- orionis/services/paths/resolver.py +6 -4
- orionis/services/standard/exceptions/__init__.py +0 -0
- orionis/services/standard/exceptions/path_value_exceptions.py +28 -0
- orionis/services/standard/std.py +4 -3
- orionis/test/entities/test_result.py +14 -1
- orionis/test/exceptions/test_persistence_error.py +34 -0
- orionis/test/exceptions/test_runtime_error.py +26 -0
- orionis/test/exceptions/test_value_error.py +26 -0
- orionis/test/logs/contracts/history.py +29 -56
- orionis/test/logs/history.py +309 -188
- orionis/test/output/contracts/dumper.py +24 -8
- orionis/test/output/dumper.py +52 -21
- orionis/test/suites/contracts/test_suite.py +27 -13
- orionis/test/suites/contracts/test_unit.py +101 -61
- orionis/test/suites/test_suite.py +45 -24
- orionis/test/suites/test_unit.py +559 -290
- orionis/unittesting.py +8 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/METADATA +1 -1
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/RECORD +44 -26
- tests/services/asynchrony/test_async_io.py +3 -2
- /orionis/services/parsers/{exception.py → exceptions/exception_parser.py} +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/WHEEL +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/top_level.txt +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/zip-safe +0 -0
orionis/test/suites/test_unit.py
CHANGED
@@ -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
|
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
|
24
|
-
import
|
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
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
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
|
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
|
269
|
+
raise OrionisTestValueError(f"Error importing tests from '{full_path}': {str(e)}")
|
177
270
|
except Exception as e:
|
178
|
-
raise
|
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
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
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
|
311
|
+
raise OrionisTestValueError(f"Error importing module '{module_name}': {str(e)}")
|
211
312
|
|
212
313
|
def _startMessage(self) -> None:
|
213
314
|
"""
|
214
|
-
|
215
|
-
|
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
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
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
|
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
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
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
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
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,
|
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
|
-
|
383
|
-
|
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
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
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
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
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
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
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
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
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
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
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
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
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
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
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
|
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
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
is
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
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
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
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
|
-
|
997
|
+
Sanitize a traceback string to extract and display the most relevant parts
|
752
998
|
related to a specific test file.
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
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
|
-
|
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]
|
1045
|
+
def _displayResults(self, summary: Dict[str, Any]) -> None:
|
793
1046
|
"""
|
794
|
-
|
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
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
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
|
-
|
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
|
-
|
862
|
-
This method processes a traceback string to extract the file path of the
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
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
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
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
|
-
|
1200
|
+
Get a list of test names (unique identifiers) from the test suite.
|
930
1201
|
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1222
|
+
Clear all tests from the current test suite.
|
954
1223
|
|
955
|
-
|
1224
|
+
Resets the internal test suite to an empty `unittest.TestSuite`, removing any previously added tests.
|
956
1225
|
"""
|
957
1226
|
self.suite = unittest.TestSuite()
|