core-tests 2.0.4__tar.gz → 2.1.0__tar.gz
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.
- {core_tests-2.0.4 → core_tests-2.1.0}/PKG-INFO +63 -100
- {core_tests-2.0.4 → core_tests-2.1.0}/README.rst +60 -97
- core_tests-2.1.0/core_tests/__init__.py +24 -0
- core_tests-2.1.0/core_tests/tests/runner.py +153 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/core_tests.egg-info/PKG-INFO +63 -100
- core_tests-2.1.0/core_tests.egg-info/requires.txt +6 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/pyproject.toml +7 -4
- core_tests-2.0.4/core_tests/tests/__init__.py +0 -0
- core_tests-2.0.4/core_tests/tests/runner.py +0 -226
- core_tests-2.0.4/core_tests.egg-info/requires.txt +0 -8
- {core_tests-2.0.4 → core_tests-2.1.0}/LICENSE +0 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/core_tests/py.typed +0 -0
- {core_tests-2.0.4/core_tests → core_tests-2.1.0/core_tests/tests}/__init__.py +0 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/core_tests/tests/base.py +0 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/core_tests.egg-info/SOURCES.txt +0 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/core_tests.egg-info/dependency_links.txt +0 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/core_tests.egg-info/top_level.txt +0 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/setup.cfg +0 -0
- {core_tests-2.0.4 → core_tests-2.1.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-tests
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: It contains common elements for testing purposes...
|
|
5
5
|
Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
|
|
6
6
|
Maintainer: Alejandro Cora González
|
|
@@ -22,26 +22,33 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
25
27
|
Requires-Python: >=3.9
|
|
26
28
|
Description-Content-Type: text/x-rst
|
|
27
29
|
License-File: LICENSE
|
|
28
30
|
Requires-Dist: click>=8.1.8
|
|
29
31
|
Requires-Dist: coverage>=7.7.1
|
|
30
32
|
Requires-Dist: environs>=14.1.1
|
|
31
|
-
Requires-Dist: pytest>=7.4.0
|
|
32
|
-
Requires-Dist: pytest-xdist>=3.5.0
|
|
33
33
|
Provides-Extra: dev
|
|
34
|
-
Requires-Dist: core-dev-tools>=
|
|
34
|
+
Requires-Dist: core-dev-tools>=2.0.0; extra == "dev"
|
|
35
35
|
Dynamic: license-file
|
|
36
36
|
|
|
37
37
|
core-tests
|
|
38
38
|
===============================================================================
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
A reusable library that provides CLI commands for running ``unittest``-based
|
|
41
|
+
tests and generating code coverage reports. It wraps Python's built-in
|
|
42
|
+
``unittest`` framework and ``coverage`` into a ``Click`` command group so
|
|
43
|
+
consuming projects can use ``python manager.py run-tests`` and
|
|
44
|
+
``python manager.py run-coverage`` without duplicating that logic across
|
|
45
|
+
every project in the ecosystem.
|
|
46
|
+
|
|
47
|
+
This library is intentionally scoped to ``unittest`` and ``coverage``.
|
|
48
|
+
If your project requires ``pytest``-specific features (fixtures, parametrize,
|
|
49
|
+
plugins, parallel execution), install ``pytest`` directly or via
|
|
50
|
+
``core-dev-tools`` and invoke it standalone — it is a better fit for that use
|
|
51
|
+
case than routing it through this abstraction layer.
|
|
45
52
|
|
|
46
53
|
===============================================================================
|
|
47
54
|
|
|
@@ -76,32 +83,35 @@ Install from PyPI using pip:
|
|
|
76
83
|
.. code-block:: bash
|
|
77
84
|
|
|
78
85
|
pip install core-tests
|
|
79
|
-
|
|
80
|
-
Or using uv:
|
|
81
|
-
|
|
82
|
-
.. code-block:: bash
|
|
83
|
-
|
|
84
|
-
uv pip install core-tests
|
|
86
|
+
uv pip install core-tests # Or using UV...
|
|
85
87
|
|
|
86
88
|
|
|
87
89
|
Features
|
|
88
90
|
===============================================================================
|
|
89
91
|
|
|
90
|
-
* **
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
* **Unified CLI abstraction**: Expose ``run-tests`` and ``run-coverage`` in any
|
|
93
|
+
project without duplicating boilerplate — just wire ``cli_tests`` into your
|
|
94
|
+
``CommandCollection``.
|
|
95
|
+
* **Flexible Test Discovery**: Supports multiple file patterns out of the box:
|
|
96
|
+
|
|
97
|
+
- ``test_*.py`` (standard pattern)
|
|
98
|
+
- ``*_test.py`` (alternative pattern)
|
|
99
|
+
- ``tests_*.py`` (custom pattern)
|
|
100
|
+
|
|
101
|
+
* **Custom Pattern Support**: Override discovery with ``--pattern`` for
|
|
102
|
+
non-standard file layouts.
|
|
103
|
+
* **Test Organization**: Target specific test directories (unit, integration,
|
|
104
|
+
functional, etc.) via ``--test-type``.
|
|
105
|
+
* **Branch Coverage Reports**: Generate branch-level coverage reports and
|
|
106
|
+
optional HTML output.
|
|
107
|
+
* **DRY principle**: One implementation shared across all projects in the
|
|
108
|
+
ecosystem.
|
|
99
109
|
|
|
100
110
|
|
|
101
111
|
How to Use
|
|
102
112
|
===============================================================================
|
|
103
113
|
|
|
104
|
-
Create a ``manager.py`` file in your project root to integrate
|
|
114
|
+
Create a ``manager.py`` file in your project root to integrate
|
|
105
115
|
the test commands:
|
|
106
116
|
|
|
107
117
|
.. code-block:: python
|
|
@@ -116,7 +126,7 @@ the test commands:
|
|
|
116
126
|
|
|
117
127
|
This setup provides two commands:
|
|
118
128
|
|
|
119
|
-
* ``run-tests``: Execute test suites
|
|
129
|
+
* ``run-tests``: Execute unittest-based test suites
|
|
120
130
|
* ``run-coverage``: Generate code coverage reports
|
|
121
131
|
|
|
122
132
|
Example usage:
|
|
@@ -124,7 +134,7 @@ Example usage:
|
|
|
124
134
|
.. code-block:: bash
|
|
125
135
|
|
|
126
136
|
python manager.py run-tests --test-type unit
|
|
127
|
-
python manager.py run-coverage
|
|
137
|
+
python manager.py run-coverage
|
|
128
138
|
|
|
129
139
|
|
|
130
140
|
Available Commands
|
|
@@ -133,49 +143,48 @@ Available Commands
|
|
|
133
143
|
run-tests
|
|
134
144
|
-------------------------------------------------------------------------------
|
|
135
145
|
|
|
136
|
-
Execute test suites with flexible options:
|
|
146
|
+
Execute unittest-based test suites with flexible options:
|
|
137
147
|
|
|
138
148
|
**Options:**
|
|
139
149
|
|
|
140
|
-
* ``--
|
|
141
|
-
|
|
142
|
-
* ``--pattern``: File pattern to match test files (e.g., ``*.py``,
|
|
150
|
+
* ``--test-type``: Folder name under ``./tests`` directory (e.g., ``unit``,
|
|
151
|
+
``integration``, ``functional``). Default: ``unit``
|
|
152
|
+
* ``--pattern``: File pattern to match test files (e.g., ``*.py``,
|
|
153
|
+
``test_*.py``). Defaults to multi-pattern discovery.
|
|
143
154
|
|
|
144
155
|
**Examples:**
|
|
145
156
|
|
|
146
157
|
.. code-block:: bash
|
|
147
158
|
|
|
148
|
-
# Run unit tests
|
|
159
|
+
# Run unit tests (default)
|
|
149
160
|
python manager.py run-tests --test-type unit
|
|
150
161
|
|
|
151
|
-
# Run integration tests
|
|
152
|
-
python manager.py run-tests --
|
|
162
|
+
# Run integration tests
|
|
163
|
+
python manager.py run-tests --test-type integration
|
|
153
164
|
|
|
154
|
-
# Run tests with custom pattern
|
|
155
|
-
python manager.py run-tests --test-type functional --pattern "
|
|
165
|
+
# Run tests with a custom file pattern
|
|
166
|
+
python manager.py run-tests --test-type functional --pattern "*.py"
|
|
156
167
|
|
|
157
|
-
# Run
|
|
168
|
+
# Run tests in a custom folder
|
|
158
169
|
python manager.py run-tests --test-type "custom_folder"
|
|
159
170
|
|
|
160
171
|
|
|
161
172
|
run-coverage
|
|
162
173
|
-------------------------------------------------------------------------------
|
|
163
174
|
|
|
164
|
-
Generate code coverage reports:
|
|
175
|
+
Generate code coverage reports across all test directories:
|
|
165
176
|
|
|
166
177
|
**Options:**
|
|
167
178
|
|
|
168
|
-
* ``--
|
|
179
|
+
* ``--save-report``: Save HTML and data coverage reports to disk.
|
|
180
|
+
Default: ``True``
|
|
169
181
|
|
|
170
182
|
**Examples:**
|
|
171
183
|
|
|
172
184
|
.. code-block:: bash
|
|
173
185
|
|
|
174
|
-
# Generate coverage with unittest
|
|
175
186
|
python manager.py run-coverage
|
|
176
|
-
|
|
177
|
-
# Generate coverage with pytest
|
|
178
|
-
python manager.py run-coverage --engine pytest
|
|
187
|
+
python manager.py run-coverage --save-report false
|
|
179
188
|
|
|
180
189
|
|
|
181
190
|
Quick Start
|
|
@@ -217,78 +226,32 @@ Tests and Coverage
|
|
|
217
226
|
|
|
218
227
|
python manager.py run-tests --test-type unit
|
|
219
228
|
python manager.py run-tests --test-type integration
|
|
220
|
-
python manager.py run-tests --test-type "another folder that contains test cases under ./tests"
|
|
221
229
|
python manager.py run-tests --test-type functional --pattern "*.py"
|
|
230
|
+
python manager.py run-coverage
|
|
222
231
|
|
|
223
232
|
|
|
224
|
-
Using
|
|
233
|
+
Using pytest directly
|
|
225
234
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
226
235
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
conventions. Pytest-style tests (i.e., functions named test_* that are not inside a
|
|
230
|
-
`unittest.TestCase` class, or tests using pytest fixtures, parametrize, etc.) are not
|
|
231
|
-
recognized by unittest's discovery mechanism, `unittest` will simply ignore standalone
|
|
232
|
-
test functions and any pytest-specific features...
|
|
233
|
-
|
|
234
|
-
That's why you can use PyTest if required.
|
|
236
|
+
``unittest`` cannot discover standalone ``test_*`` functions or use pytest
|
|
237
|
+
fixtures. If your project relies on those features, invoke ``pytest`` directly:
|
|
235
238
|
|
|
236
239
|
.. code-block:: bash
|
|
237
240
|
|
|
238
|
-
|
|
241
|
+
pytest tests/unit/
|
|
242
|
+
pytest -n auto --cov=your_package --cov-report=html
|
|
239
243
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
Test coverage
|
|
243
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
244
|
+
Install ``pytest`` via ``pip`` or through ``core-dev-tools``:
|
|
244
245
|
|
|
245
246
|
.. code-block:: bash
|
|
246
247
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
pip install pytest pytest-xdist pytest-cov
|
|
249
|
+
# or
|
|
250
|
+
pip install ".[dev]" # if core-dev-tools includes pytest
|
|
250
251
|
|
|
251
252
|
..
|
|
252
253
|
|
|
253
254
|
|
|
254
|
-
Best Practices
|
|
255
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
256
|
-
|
|
257
|
-
When working with pytest, consider these optimization strategies:
|
|
258
|
-
|
|
259
|
-
1. **Use parallel execution for independent tests:**
|
|
260
|
-
|
|
261
|
-
.. code-block:: bash
|
|
262
|
-
|
|
263
|
-
pytest -n auto
|
|
264
|
-
|
|
265
|
-
..
|
|
266
|
-
|
|
267
|
-
2. **Run fast unit tests first during development:**
|
|
268
|
-
|
|
269
|
-
.. code-block:: bash
|
|
270
|
-
|
|
271
|
-
pytest tests/unit/ -n auto
|
|
272
|
-
|
|
273
|
-
..
|
|
274
|
-
|
|
275
|
-
3. **Run functional tests with limited parallelism:**
|
|
276
|
-
|
|
277
|
-
.. code-block:: bash
|
|
278
|
-
|
|
279
|
-
pytest tests/functional/ -n 2 # Avoid AWS rate limits
|
|
280
|
-
|
|
281
|
-
..
|
|
282
|
-
|
|
283
|
-
4. **Use markers to run specific test subsets:**
|
|
284
|
-
|
|
285
|
-
.. code-block:: bash
|
|
286
|
-
|
|
287
|
-
pytest -m "unit and not slow" -n auto
|
|
288
|
-
|
|
289
|
-
..
|
|
290
|
-
|
|
291
|
-
|
|
292
255
|
Contributing
|
|
293
256
|
===============================================================================
|
|
294
257
|
|
|
@@ -297,7 +260,7 @@ Contributions are welcome! Please:
|
|
|
297
260
|
1. Fork the repository
|
|
298
261
|
2. Create a feature branch
|
|
299
262
|
3. Write tests for new functionality
|
|
300
|
-
4. Ensure all tests pass: ``
|
|
263
|
+
4. Ensure all tests pass: ``python manager.py run-tests --test-type unit``
|
|
301
264
|
5. Run linting: ``pylint core_tests``
|
|
302
265
|
6. Run security checks: ``bandit -r core_tests``
|
|
303
266
|
7. Submit a pull request
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
core-tests
|
|
2
2
|
===============================================================================
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
A reusable library that provides CLI commands for running ``unittest``-based
|
|
5
|
+
tests and generating code coverage reports. It wraps Python's built-in
|
|
6
|
+
``unittest`` framework and ``coverage`` into a ``Click`` command group so
|
|
7
|
+
consuming projects can use ``python manager.py run-tests`` and
|
|
8
|
+
``python manager.py run-coverage`` without duplicating that logic across
|
|
9
|
+
every project in the ecosystem.
|
|
10
|
+
|
|
11
|
+
This library is intentionally scoped to ``unittest`` and ``coverage``.
|
|
12
|
+
If your project requires ``pytest``-specific features (fixtures, parametrize,
|
|
13
|
+
plugins, parallel execution), install ``pytest`` directly or via
|
|
14
|
+
``core-dev-tools`` and invoke it standalone — it is a better fit for that use
|
|
15
|
+
case than routing it through this abstraction layer.
|
|
9
16
|
|
|
10
17
|
===============================================================================
|
|
11
18
|
|
|
@@ -40,32 +47,35 @@ Install from PyPI using pip:
|
|
|
40
47
|
.. code-block:: bash
|
|
41
48
|
|
|
42
49
|
pip install core-tests
|
|
43
|
-
|
|
44
|
-
Or using uv:
|
|
45
|
-
|
|
46
|
-
.. code-block:: bash
|
|
47
|
-
|
|
48
|
-
uv pip install core-tests
|
|
50
|
+
uv pip install core-tests # Or using UV...
|
|
49
51
|
|
|
50
52
|
|
|
51
53
|
Features
|
|
52
54
|
===============================================================================
|
|
53
55
|
|
|
54
|
-
* **
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
* **Unified CLI abstraction**: Expose ``run-tests`` and ``run-coverage`` in any
|
|
57
|
+
project without duplicating boilerplate — just wire ``cli_tests`` into your
|
|
58
|
+
``CommandCollection``.
|
|
59
|
+
* **Flexible Test Discovery**: Supports multiple file patterns out of the box:
|
|
60
|
+
|
|
61
|
+
- ``test_*.py`` (standard pattern)
|
|
62
|
+
- ``*_test.py`` (alternative pattern)
|
|
63
|
+
- ``tests_*.py`` (custom pattern)
|
|
64
|
+
|
|
65
|
+
* **Custom Pattern Support**: Override discovery with ``--pattern`` for
|
|
66
|
+
non-standard file layouts.
|
|
67
|
+
* **Test Organization**: Target specific test directories (unit, integration,
|
|
68
|
+
functional, etc.) via ``--test-type``.
|
|
69
|
+
* **Branch Coverage Reports**: Generate branch-level coverage reports and
|
|
70
|
+
optional HTML output.
|
|
71
|
+
* **DRY principle**: One implementation shared across all projects in the
|
|
72
|
+
ecosystem.
|
|
63
73
|
|
|
64
74
|
|
|
65
75
|
How to Use
|
|
66
76
|
===============================================================================
|
|
67
77
|
|
|
68
|
-
Create a ``manager.py`` file in your project root to integrate
|
|
78
|
+
Create a ``manager.py`` file in your project root to integrate
|
|
69
79
|
the test commands:
|
|
70
80
|
|
|
71
81
|
.. code-block:: python
|
|
@@ -80,7 +90,7 @@ the test commands:
|
|
|
80
90
|
|
|
81
91
|
This setup provides two commands:
|
|
82
92
|
|
|
83
|
-
* ``run-tests``: Execute test suites
|
|
93
|
+
* ``run-tests``: Execute unittest-based test suites
|
|
84
94
|
* ``run-coverage``: Generate code coverage reports
|
|
85
95
|
|
|
86
96
|
Example usage:
|
|
@@ -88,7 +98,7 @@ Example usage:
|
|
|
88
98
|
.. code-block:: bash
|
|
89
99
|
|
|
90
100
|
python manager.py run-tests --test-type unit
|
|
91
|
-
python manager.py run-coverage
|
|
101
|
+
python manager.py run-coverage
|
|
92
102
|
|
|
93
103
|
|
|
94
104
|
Available Commands
|
|
@@ -97,49 +107,48 @@ Available Commands
|
|
|
97
107
|
run-tests
|
|
98
108
|
-------------------------------------------------------------------------------
|
|
99
109
|
|
|
100
|
-
Execute test suites with flexible options:
|
|
110
|
+
Execute unittest-based test suites with flexible options:
|
|
101
111
|
|
|
102
112
|
**Options:**
|
|
103
113
|
|
|
104
|
-
* ``--
|
|
105
|
-
|
|
106
|
-
* ``--pattern``: File pattern to match test files (e.g., ``*.py``,
|
|
114
|
+
* ``--test-type``: Folder name under ``./tests`` directory (e.g., ``unit``,
|
|
115
|
+
``integration``, ``functional``). Default: ``unit``
|
|
116
|
+
* ``--pattern``: File pattern to match test files (e.g., ``*.py``,
|
|
117
|
+
``test_*.py``). Defaults to multi-pattern discovery.
|
|
107
118
|
|
|
108
119
|
**Examples:**
|
|
109
120
|
|
|
110
121
|
.. code-block:: bash
|
|
111
122
|
|
|
112
|
-
# Run unit tests
|
|
123
|
+
# Run unit tests (default)
|
|
113
124
|
python manager.py run-tests --test-type unit
|
|
114
125
|
|
|
115
|
-
# Run integration tests
|
|
116
|
-
python manager.py run-tests --
|
|
126
|
+
# Run integration tests
|
|
127
|
+
python manager.py run-tests --test-type integration
|
|
117
128
|
|
|
118
|
-
# Run tests with custom pattern
|
|
119
|
-
python manager.py run-tests --test-type functional --pattern "
|
|
129
|
+
# Run tests with a custom file pattern
|
|
130
|
+
python manager.py run-tests --test-type functional --pattern "*.py"
|
|
120
131
|
|
|
121
|
-
# Run
|
|
132
|
+
# Run tests in a custom folder
|
|
122
133
|
python manager.py run-tests --test-type "custom_folder"
|
|
123
134
|
|
|
124
135
|
|
|
125
136
|
run-coverage
|
|
126
137
|
-------------------------------------------------------------------------------
|
|
127
138
|
|
|
128
|
-
Generate code coverage reports:
|
|
139
|
+
Generate code coverage reports across all test directories:
|
|
129
140
|
|
|
130
141
|
**Options:**
|
|
131
142
|
|
|
132
|
-
* ``--
|
|
143
|
+
* ``--save-report``: Save HTML and data coverage reports to disk.
|
|
144
|
+
Default: ``True``
|
|
133
145
|
|
|
134
146
|
**Examples:**
|
|
135
147
|
|
|
136
148
|
.. code-block:: bash
|
|
137
149
|
|
|
138
|
-
# Generate coverage with unittest
|
|
139
150
|
python manager.py run-coverage
|
|
140
|
-
|
|
141
|
-
# Generate coverage with pytest
|
|
142
|
-
python manager.py run-coverage --engine pytest
|
|
151
|
+
python manager.py run-coverage --save-report false
|
|
143
152
|
|
|
144
153
|
|
|
145
154
|
Quick Start
|
|
@@ -181,78 +190,32 @@ Tests and Coverage
|
|
|
181
190
|
|
|
182
191
|
python manager.py run-tests --test-type unit
|
|
183
192
|
python manager.py run-tests --test-type integration
|
|
184
|
-
python manager.py run-tests --test-type "another folder that contains test cases under ./tests"
|
|
185
193
|
python manager.py run-tests --test-type functional --pattern "*.py"
|
|
194
|
+
python manager.py run-coverage
|
|
186
195
|
|
|
187
196
|
|
|
188
|
-
Using
|
|
197
|
+
Using pytest directly
|
|
189
198
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
190
199
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
conventions. Pytest-style tests (i.e., functions named test_* that are not inside a
|
|
194
|
-
`unittest.TestCase` class, or tests using pytest fixtures, parametrize, etc.) are not
|
|
195
|
-
recognized by unittest's discovery mechanism, `unittest` will simply ignore standalone
|
|
196
|
-
test functions and any pytest-specific features...
|
|
197
|
-
|
|
198
|
-
That's why you can use PyTest if required.
|
|
200
|
+
``unittest`` cannot discover standalone ``test_*`` functions or use pytest
|
|
201
|
+
fixtures. If your project relies on those features, invoke ``pytest`` directly:
|
|
199
202
|
|
|
200
203
|
.. code-block:: bash
|
|
201
204
|
|
|
202
|
-
|
|
205
|
+
pytest tests/unit/
|
|
206
|
+
pytest -n auto --cov=your_package --cov-report=html
|
|
203
207
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
Test coverage
|
|
207
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
208
|
+
Install ``pytest`` via ``pip`` or through ``core-dev-tools``:
|
|
208
209
|
|
|
209
210
|
.. code-block:: bash
|
|
210
211
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
pip install pytest pytest-xdist pytest-cov
|
|
213
|
+
# or
|
|
214
|
+
pip install ".[dev]" # if core-dev-tools includes pytest
|
|
214
215
|
|
|
215
216
|
..
|
|
216
217
|
|
|
217
218
|
|
|
218
|
-
Best Practices
|
|
219
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
220
|
-
|
|
221
|
-
When working with pytest, consider these optimization strategies:
|
|
222
|
-
|
|
223
|
-
1. **Use parallel execution for independent tests:**
|
|
224
|
-
|
|
225
|
-
.. code-block:: bash
|
|
226
|
-
|
|
227
|
-
pytest -n auto
|
|
228
|
-
|
|
229
|
-
..
|
|
230
|
-
|
|
231
|
-
2. **Run fast unit tests first during development:**
|
|
232
|
-
|
|
233
|
-
.. code-block:: bash
|
|
234
|
-
|
|
235
|
-
pytest tests/unit/ -n auto
|
|
236
|
-
|
|
237
|
-
..
|
|
238
|
-
|
|
239
|
-
3. **Run functional tests with limited parallelism:**
|
|
240
|
-
|
|
241
|
-
.. code-block:: bash
|
|
242
|
-
|
|
243
|
-
pytest tests/functional/ -n 2 # Avoid AWS rate limits
|
|
244
|
-
|
|
245
|
-
..
|
|
246
|
-
|
|
247
|
-
4. **Use markers to run specific test subsets:**
|
|
248
|
-
|
|
249
|
-
.. code-block:: bash
|
|
250
|
-
|
|
251
|
-
pytest -m "unit and not slow" -n auto
|
|
252
|
-
|
|
253
|
-
..
|
|
254
|
-
|
|
255
|
-
|
|
256
219
|
Contributing
|
|
257
220
|
===============================================================================
|
|
258
221
|
|
|
@@ -261,7 +224,7 @@ Contributions are welcome! Please:
|
|
|
261
224
|
1. Fork the repository
|
|
262
225
|
2. Create a feature branch
|
|
263
226
|
3. Write tests for new functionality
|
|
264
|
-
4. Ensure all tests pass: ``
|
|
227
|
+
4. Ensure all tests pass: ``python manager.py run-tests --test-type unit``
|
|
265
228
|
5. Run linting: ``pylint core_tests``
|
|
266
229
|
6. Run security checks: ``bandit -r core_tests``
|
|
267
230
|
7. Submit a pull request
|
|
@@ -292,4 +255,4 @@ For questions or support, please open an issue on GitLab or contact the maintain
|
|
|
292
255
|
Authors
|
|
293
256
|
===============================================================================
|
|
294
257
|
|
|
295
|
-
* **Alejandro Cora González** - *Initial work* - alek.cora.glez@gmail.com
|
|
258
|
+
* **Alejandro Cora González** - *Initial work* - alek.cora.glez@gmail.com
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Provides common elements for testing purposes.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from importlib.metadata import PackageNotFoundError
|
|
8
|
+
from importlib.metadata import version
|
|
9
|
+
|
|
10
|
+
from core_tests.tests.base import BaseTestCase
|
|
11
|
+
from core_tests.tests.runner import cli_tests
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
__version__ = version("core-tests")
|
|
15
|
+
|
|
16
|
+
except PackageNotFoundError:
|
|
17
|
+
__version__ = "unknown"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"__version__",
|
|
22
|
+
"BaseTestCase",
|
|
23
|
+
"cli_tests",
|
|
24
|
+
]
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
This module provides a group of CLI commands that abstract unittest-based
|
|
5
|
+
test execution and code coverage measurement. Consuming projects import
|
|
6
|
+
``cli_tests`` and wire it into their own ``CommandCollection`` to expose
|
|
7
|
+
``run-tests`` and ``run-coverage`` without duplicating this logic.
|
|
8
|
+
|
|
9
|
+
This library is intentionally scoped to ``unittest`` and ``coverage``. If your
|
|
10
|
+
project requires pytest-specific features (fixtures, parametrize, plugins),
|
|
11
|
+
install ``pytest`` directly or via ``core-dev-tools`` and invoke it standalone.
|
|
12
|
+
|
|
13
|
+
**Test File Discovery:**
|
|
14
|
+
|
|
15
|
+
By default, (``tests_*.py``), ``run-tests`` runs discovery across all three
|
|
16
|
+
built-in patterns: ``test_*.py``, ``*_test.py``, and ``tests_*.py``.
|
|
17
|
+
Supply ``--pattern`` with any other glob to target a specific naming
|
|
18
|
+
convention instead.
|
|
19
|
+
|
|
20
|
+
Tests that connect to real external services should use a naming convention
|
|
21
|
+
that falls outside these patterns (e.g. ``check_*.py``) so they are not
|
|
22
|
+
picked up automatically.
|
|
23
|
+
|
|
24
|
+
**Available Commands:**
|
|
25
|
+
|
|
26
|
+
* ``python manager.py run-tests``
|
|
27
|
+
* ``python manager.py run-tests --test-type unit``
|
|
28
|
+
* ``python manager.py run-tests --test-type integration``
|
|
29
|
+
* ``python manager.py run-tests --test-type functional --pattern "*.py"``
|
|
30
|
+
* ``python manager.py run-coverage``
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import logging
|
|
36
|
+
import os
|
|
37
|
+
import sys
|
|
38
|
+
import typing
|
|
39
|
+
from unittest import TestCase
|
|
40
|
+
from unittest import TestLoader
|
|
41
|
+
from unittest import TestSuite
|
|
42
|
+
from unittest import TextTestRunner
|
|
43
|
+
|
|
44
|
+
from click import echo, option
|
|
45
|
+
from click.decorators import group
|
|
46
|
+
from coverage import coverage, CoverageException
|
|
47
|
+
|
|
48
|
+
patterns = [
|
|
49
|
+
"test_*.py",
|
|
50
|
+
"*_test.py",
|
|
51
|
+
"tests_*.py",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@group()
|
|
56
|
+
def cli_tests():
|
|
57
|
+
"""
|
|
58
|
+
Group of commands related to tests.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@cli_tests.command("run-tests")
|
|
63
|
+
@option("-t", "--test-type", "test_type", default="unit")
|
|
64
|
+
@option("-p", "--pattern", "pattern", default="tests_*.py")
|
|
65
|
+
def run_tests(test_type: str, pattern: str) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Runs unittest-based tests in a specific directory.
|
|
68
|
+
|
|
69
|
+
:param test_type: Directory name under ./tests/ (e.g., 'unit', 'integration', 'functional').
|
|
70
|
+
:param pattern: File glob pattern passed to ``TestLoader.discover``.
|
|
71
|
+
|
|
72
|
+
Pattern Usage:
|
|
73
|
+
- Default ``tests_*.py`` runs discovery across all three built-in
|
|
74
|
+
patterns: ``test_*.py``, ``*_test.py``, and ``tests_*.py``.
|
|
75
|
+
- Any other glob (e.g. ``test*.py``, ``*_test.py``, ``*.py``) runs a
|
|
76
|
+
single ``TestLoader.discover`` call with that pattern.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
if not os.path.exists(f"./tests/{test_type}"):
|
|
80
|
+
echo(f"The directory: {test_type} does not exist under ./tests!", err=True)
|
|
81
|
+
sys.exit(1)
|
|
82
|
+
|
|
83
|
+
if test_type == "unit":
|
|
84
|
+
# Just removing verbosity from unit tests...
|
|
85
|
+
level = os.getenv("LOGGER_LEVEL_FOR_TEST", str(logging.ERROR))
|
|
86
|
+
os.environ["LOGGER_LEVEL"] = level
|
|
87
|
+
|
|
88
|
+
all_tests: typing.List[TestCase | TestSuite] = []
|
|
89
|
+
|
|
90
|
+
if pattern != "tests_*.py":
|
|
91
|
+
tests = TestLoader().discover(f"./tests/{test_type}", pattern=pattern)
|
|
92
|
+
all_tests.extend(tests)
|
|
93
|
+
|
|
94
|
+
else:
|
|
95
|
+
for pattern_glob in patterns:
|
|
96
|
+
tests = TestLoader().discover(f"./tests/{test_type}", pattern=pattern_glob)
|
|
97
|
+
all_tests.extend(tests)
|
|
98
|
+
|
|
99
|
+
result = TextTestRunner(verbosity=2).run(TestSuite(all_tests))
|
|
100
|
+
if not result.wasSuccessful():
|
|
101
|
+
sys.exit(1)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@cli_tests.command("run-coverage")
|
|
105
|
+
@option("-s", "--save-report", "save_report", default=True)
|
|
106
|
+
def run_coverage(save_report: bool) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Runs all tests across all test directories and generates a coverage report.
|
|
109
|
+
|
|
110
|
+
:param save_report: Whether to save HTML and data coverage reports to disk.
|
|
111
|
+
:type save_report: bool
|
|
112
|
+
|
|
113
|
+
Coverage Analysis:
|
|
114
|
+
- Runs tests with branch coverage enabled.
|
|
115
|
+
- Analyzes all source files in current directory.
|
|
116
|
+
- Generates console report summary.
|
|
117
|
+
- Optionally saves HTML report (default: True).
|
|
118
|
+
|
|
119
|
+
File Discovery:
|
|
120
|
+
Automatically finds files matching: ``test_*.py``, ``*_test.py``, ``tests_*.py``
|
|
121
|
+
across all subdirectories under ``./tests/``. It means that functional or integration
|
|
122
|
+
tests that connect to real services should be named with other pattern,
|
|
123
|
+
like ``check_aws_integration``.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
os.environ["LOGGER_LEVEL"] = os.getenv("LOGGER_LEVEL_FOR_TEST", str(logging.ERROR))
|
|
127
|
+
coverage_ = coverage(branch=True, source=["."])
|
|
128
|
+
coverage_.start()
|
|
129
|
+
|
|
130
|
+
all_tests: typing.List[TestCase | TestSuite] = []
|
|
131
|
+
for pattern_glob in patterns:
|
|
132
|
+
tests = TestLoader().discover("./tests", pattern=pattern_glob)
|
|
133
|
+
all_tests.extend(tests)
|
|
134
|
+
|
|
135
|
+
result = TextTestRunner(verbosity=3).run(TestSuite(all_tests))
|
|
136
|
+
if not result.wasSuccessful():
|
|
137
|
+
sys.exit(1)
|
|
138
|
+
|
|
139
|
+
coverage_.stop()
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
echo("Coverage Summary:")
|
|
143
|
+
coverage_.report()
|
|
144
|
+
|
|
145
|
+
if save_report:
|
|
146
|
+
coverage_.save()
|
|
147
|
+
coverage_.html_report()
|
|
148
|
+
|
|
149
|
+
coverage_.erase()
|
|
150
|
+
|
|
151
|
+
except CoverageException as error:
|
|
152
|
+
echo(error)
|
|
153
|
+
sys.exit(1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-tests
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: It contains common elements for testing purposes...
|
|
5
5
|
Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
|
|
6
6
|
Maintainer: Alejandro Cora González
|
|
@@ -22,26 +22,33 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
25
27
|
Requires-Python: >=3.9
|
|
26
28
|
Description-Content-Type: text/x-rst
|
|
27
29
|
License-File: LICENSE
|
|
28
30
|
Requires-Dist: click>=8.1.8
|
|
29
31
|
Requires-Dist: coverage>=7.7.1
|
|
30
32
|
Requires-Dist: environs>=14.1.1
|
|
31
|
-
Requires-Dist: pytest>=7.4.0
|
|
32
|
-
Requires-Dist: pytest-xdist>=3.5.0
|
|
33
33
|
Provides-Extra: dev
|
|
34
|
-
Requires-Dist: core-dev-tools>=
|
|
34
|
+
Requires-Dist: core-dev-tools>=2.0.0; extra == "dev"
|
|
35
35
|
Dynamic: license-file
|
|
36
36
|
|
|
37
37
|
core-tests
|
|
38
38
|
===============================================================================
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
A reusable library that provides CLI commands for running ``unittest``-based
|
|
41
|
+
tests and generating code coverage reports. It wraps Python's built-in
|
|
42
|
+
``unittest`` framework and ``coverage`` into a ``Click`` command group so
|
|
43
|
+
consuming projects can use ``python manager.py run-tests`` and
|
|
44
|
+
``python manager.py run-coverage`` without duplicating that logic across
|
|
45
|
+
every project in the ecosystem.
|
|
46
|
+
|
|
47
|
+
This library is intentionally scoped to ``unittest`` and ``coverage``.
|
|
48
|
+
If your project requires ``pytest``-specific features (fixtures, parametrize,
|
|
49
|
+
plugins, parallel execution), install ``pytest`` directly or via
|
|
50
|
+
``core-dev-tools`` and invoke it standalone — it is a better fit for that use
|
|
51
|
+
case than routing it through this abstraction layer.
|
|
45
52
|
|
|
46
53
|
===============================================================================
|
|
47
54
|
|
|
@@ -76,32 +83,35 @@ Install from PyPI using pip:
|
|
|
76
83
|
.. code-block:: bash
|
|
77
84
|
|
|
78
85
|
pip install core-tests
|
|
79
|
-
|
|
80
|
-
Or using uv:
|
|
81
|
-
|
|
82
|
-
.. code-block:: bash
|
|
83
|
-
|
|
84
|
-
uv pip install core-tests
|
|
86
|
+
uv pip install core-tests # Or using UV...
|
|
85
87
|
|
|
86
88
|
|
|
87
89
|
Features
|
|
88
90
|
===============================================================================
|
|
89
91
|
|
|
90
|
-
* **
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
* **Unified CLI abstraction**: Expose ``run-tests`` and ``run-coverage`` in any
|
|
93
|
+
project without duplicating boilerplate — just wire ``cli_tests`` into your
|
|
94
|
+
``CommandCollection``.
|
|
95
|
+
* **Flexible Test Discovery**: Supports multiple file patterns out of the box:
|
|
96
|
+
|
|
97
|
+
- ``test_*.py`` (standard pattern)
|
|
98
|
+
- ``*_test.py`` (alternative pattern)
|
|
99
|
+
- ``tests_*.py`` (custom pattern)
|
|
100
|
+
|
|
101
|
+
* **Custom Pattern Support**: Override discovery with ``--pattern`` for
|
|
102
|
+
non-standard file layouts.
|
|
103
|
+
* **Test Organization**: Target specific test directories (unit, integration,
|
|
104
|
+
functional, etc.) via ``--test-type``.
|
|
105
|
+
* **Branch Coverage Reports**: Generate branch-level coverage reports and
|
|
106
|
+
optional HTML output.
|
|
107
|
+
* **DRY principle**: One implementation shared across all projects in the
|
|
108
|
+
ecosystem.
|
|
99
109
|
|
|
100
110
|
|
|
101
111
|
How to Use
|
|
102
112
|
===============================================================================
|
|
103
113
|
|
|
104
|
-
Create a ``manager.py`` file in your project root to integrate
|
|
114
|
+
Create a ``manager.py`` file in your project root to integrate
|
|
105
115
|
the test commands:
|
|
106
116
|
|
|
107
117
|
.. code-block:: python
|
|
@@ -116,7 +126,7 @@ the test commands:
|
|
|
116
126
|
|
|
117
127
|
This setup provides two commands:
|
|
118
128
|
|
|
119
|
-
* ``run-tests``: Execute test suites
|
|
129
|
+
* ``run-tests``: Execute unittest-based test suites
|
|
120
130
|
* ``run-coverage``: Generate code coverage reports
|
|
121
131
|
|
|
122
132
|
Example usage:
|
|
@@ -124,7 +134,7 @@ Example usage:
|
|
|
124
134
|
.. code-block:: bash
|
|
125
135
|
|
|
126
136
|
python manager.py run-tests --test-type unit
|
|
127
|
-
python manager.py run-coverage
|
|
137
|
+
python manager.py run-coverage
|
|
128
138
|
|
|
129
139
|
|
|
130
140
|
Available Commands
|
|
@@ -133,49 +143,48 @@ Available Commands
|
|
|
133
143
|
run-tests
|
|
134
144
|
-------------------------------------------------------------------------------
|
|
135
145
|
|
|
136
|
-
Execute test suites with flexible options:
|
|
146
|
+
Execute unittest-based test suites with flexible options:
|
|
137
147
|
|
|
138
148
|
**Options:**
|
|
139
149
|
|
|
140
|
-
* ``--
|
|
141
|
-
|
|
142
|
-
* ``--pattern``: File pattern to match test files (e.g., ``*.py``,
|
|
150
|
+
* ``--test-type``: Folder name under ``./tests`` directory (e.g., ``unit``,
|
|
151
|
+
``integration``, ``functional``). Default: ``unit``
|
|
152
|
+
* ``--pattern``: File pattern to match test files (e.g., ``*.py``,
|
|
153
|
+
``test_*.py``). Defaults to multi-pattern discovery.
|
|
143
154
|
|
|
144
155
|
**Examples:**
|
|
145
156
|
|
|
146
157
|
.. code-block:: bash
|
|
147
158
|
|
|
148
|
-
# Run unit tests
|
|
159
|
+
# Run unit tests (default)
|
|
149
160
|
python manager.py run-tests --test-type unit
|
|
150
161
|
|
|
151
|
-
# Run integration tests
|
|
152
|
-
python manager.py run-tests --
|
|
162
|
+
# Run integration tests
|
|
163
|
+
python manager.py run-tests --test-type integration
|
|
153
164
|
|
|
154
|
-
# Run tests with custom pattern
|
|
155
|
-
python manager.py run-tests --test-type functional --pattern "
|
|
165
|
+
# Run tests with a custom file pattern
|
|
166
|
+
python manager.py run-tests --test-type functional --pattern "*.py"
|
|
156
167
|
|
|
157
|
-
# Run
|
|
168
|
+
# Run tests in a custom folder
|
|
158
169
|
python manager.py run-tests --test-type "custom_folder"
|
|
159
170
|
|
|
160
171
|
|
|
161
172
|
run-coverage
|
|
162
173
|
-------------------------------------------------------------------------------
|
|
163
174
|
|
|
164
|
-
Generate code coverage reports:
|
|
175
|
+
Generate code coverage reports across all test directories:
|
|
165
176
|
|
|
166
177
|
**Options:**
|
|
167
178
|
|
|
168
|
-
* ``--
|
|
179
|
+
* ``--save-report``: Save HTML and data coverage reports to disk.
|
|
180
|
+
Default: ``True``
|
|
169
181
|
|
|
170
182
|
**Examples:**
|
|
171
183
|
|
|
172
184
|
.. code-block:: bash
|
|
173
185
|
|
|
174
|
-
# Generate coverage with unittest
|
|
175
186
|
python manager.py run-coverage
|
|
176
|
-
|
|
177
|
-
# Generate coverage with pytest
|
|
178
|
-
python manager.py run-coverage --engine pytest
|
|
187
|
+
python manager.py run-coverage --save-report false
|
|
179
188
|
|
|
180
189
|
|
|
181
190
|
Quick Start
|
|
@@ -217,78 +226,32 @@ Tests and Coverage
|
|
|
217
226
|
|
|
218
227
|
python manager.py run-tests --test-type unit
|
|
219
228
|
python manager.py run-tests --test-type integration
|
|
220
|
-
python manager.py run-tests --test-type "another folder that contains test cases under ./tests"
|
|
221
229
|
python manager.py run-tests --test-type functional --pattern "*.py"
|
|
230
|
+
python manager.py run-coverage
|
|
222
231
|
|
|
223
232
|
|
|
224
|
-
Using
|
|
233
|
+
Using pytest directly
|
|
225
234
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
226
235
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
conventions. Pytest-style tests (i.e., functions named test_* that are not inside a
|
|
230
|
-
`unittest.TestCase` class, or tests using pytest fixtures, parametrize, etc.) are not
|
|
231
|
-
recognized by unittest's discovery mechanism, `unittest` will simply ignore standalone
|
|
232
|
-
test functions and any pytest-specific features...
|
|
233
|
-
|
|
234
|
-
That's why you can use PyTest if required.
|
|
236
|
+
``unittest`` cannot discover standalone ``test_*`` functions or use pytest
|
|
237
|
+
fixtures. If your project relies on those features, invoke ``pytest`` directly:
|
|
235
238
|
|
|
236
239
|
.. code-block:: bash
|
|
237
240
|
|
|
238
|
-
|
|
241
|
+
pytest tests/unit/
|
|
242
|
+
pytest -n auto --cov=your_package --cov-report=html
|
|
239
243
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
Test coverage
|
|
243
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
244
|
+
Install ``pytest`` via ``pip`` or through ``core-dev-tools``:
|
|
244
245
|
|
|
245
246
|
.. code-block:: bash
|
|
246
247
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
pip install pytest pytest-xdist pytest-cov
|
|
249
|
+
# or
|
|
250
|
+
pip install ".[dev]" # if core-dev-tools includes pytest
|
|
250
251
|
|
|
251
252
|
..
|
|
252
253
|
|
|
253
254
|
|
|
254
|
-
Best Practices
|
|
255
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
256
|
-
|
|
257
|
-
When working with pytest, consider these optimization strategies:
|
|
258
|
-
|
|
259
|
-
1. **Use parallel execution for independent tests:**
|
|
260
|
-
|
|
261
|
-
.. code-block:: bash
|
|
262
|
-
|
|
263
|
-
pytest -n auto
|
|
264
|
-
|
|
265
|
-
..
|
|
266
|
-
|
|
267
|
-
2. **Run fast unit tests first during development:**
|
|
268
|
-
|
|
269
|
-
.. code-block:: bash
|
|
270
|
-
|
|
271
|
-
pytest tests/unit/ -n auto
|
|
272
|
-
|
|
273
|
-
..
|
|
274
|
-
|
|
275
|
-
3. **Run functional tests with limited parallelism:**
|
|
276
|
-
|
|
277
|
-
.. code-block:: bash
|
|
278
|
-
|
|
279
|
-
pytest tests/functional/ -n 2 # Avoid AWS rate limits
|
|
280
|
-
|
|
281
|
-
..
|
|
282
|
-
|
|
283
|
-
4. **Use markers to run specific test subsets:**
|
|
284
|
-
|
|
285
|
-
.. code-block:: bash
|
|
286
|
-
|
|
287
|
-
pytest -m "unit and not slow" -n auto
|
|
288
|
-
|
|
289
|
-
..
|
|
290
|
-
|
|
291
|
-
|
|
292
255
|
Contributing
|
|
293
256
|
===============================================================================
|
|
294
257
|
|
|
@@ -297,7 +260,7 @@ Contributions are welcome! Please:
|
|
|
297
260
|
1. Fork the repository
|
|
298
261
|
2. Create a feature branch
|
|
299
262
|
3. Write tests for new functionality
|
|
300
|
-
4. Ensure all tests pass: ``
|
|
263
|
+
4. Ensure all tests pass: ``python manager.py run-tests --test-type unit``
|
|
301
264
|
5. Run linting: ``pylint core_tests``
|
|
302
265
|
6. Run security checks: ``bandit -r core_tests``
|
|
303
266
|
7. Submit a pull request
|
|
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "core-tests"
|
|
11
|
-
version = "2.0
|
|
11
|
+
version = "2.1.0"
|
|
12
12
|
|
|
13
13
|
description = """It contains common elements for testing purposes..."""
|
|
14
14
|
|
|
@@ -38,19 +38,19 @@ classifiers = [
|
|
|
38
38
|
"Programming Language :: Python :: 3.11",
|
|
39
39
|
"Programming Language :: Python :: 3.12",
|
|
40
40
|
"Programming Language :: Python :: 3.13",
|
|
41
|
+
"Programming Language :: Python :: 3.14",
|
|
42
|
+
"Programming Language :: Python :: Implementation :: PyPy",
|
|
41
43
|
]
|
|
42
44
|
|
|
43
45
|
dependencies = [
|
|
44
46
|
"click>=8.1.8",
|
|
45
47
|
"coverage>=7.7.1",
|
|
46
48
|
"environs>=14.1.1",
|
|
47
|
-
"pytest>=7.4.0",
|
|
48
|
-
"pytest-xdist>=3.5.0",
|
|
49
49
|
]
|
|
50
50
|
|
|
51
51
|
[project.optional-dependencies]
|
|
52
52
|
dev = [
|
|
53
|
-
"core-dev-tools>=
|
|
53
|
+
"core-dev-tools>=2.0.0",
|
|
54
54
|
]
|
|
55
55
|
|
|
56
56
|
[project.urls]
|
|
@@ -60,5 +60,8 @@ Documentation = "https://core-tests.readthedocs.io/en/latest/"
|
|
|
60
60
|
Issues = "https://gitlab.com/bytecode-solutions/core/core-tests/-/issues"
|
|
61
61
|
Changelog = "https://gitlab.com/bytecode-solutions/core/core-tests/-/blob/master/CHANGELOG.md"
|
|
62
62
|
|
|
63
|
+
[tool.pytest.ini_options]
|
|
64
|
+
python_files = ["test_*.py", "*_test.py", "tests_*.py"]
|
|
65
|
+
|
|
63
66
|
[tool.setuptools.package-data]
|
|
64
67
|
"core_tests" = ["py.typed"]
|
|
File without changes
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
This module provides a group of commands related to tests, this way we
|
|
5
|
-
avoid defining them in each project that requires them.
|
|
6
|
-
|
|
7
|
-
**Test File Discovery:**
|
|
8
|
-
|
|
9
|
-
Automatically discovers test files matching these patterns:
|
|
10
|
-
* ``test_*.py`` (standard pytest/unittest pattern)
|
|
11
|
-
* ``*_test.py`` (standard pytest pattern)
|
|
12
|
-
* ``tests_*.py`` (legacy pattern support)
|
|
13
|
-
|
|
14
|
-
Available Commands:
|
|
15
|
-
* python manager.py run-tests --test-type unit
|
|
16
|
-
* python manager.py run-tests --test-type integration
|
|
17
|
-
* python manager.py run-tests --test-type functional
|
|
18
|
-
* python manager.py run-tests --engine pytest
|
|
19
|
-
* python manager.py run-tests --pattern "test_specific"
|
|
20
|
-
* python manager.py run-coverage
|
|
21
|
-
* python manager.py run-coverage --engine pytest
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
from __future__ import annotations
|
|
25
|
-
|
|
26
|
-
import glob
|
|
27
|
-
import logging
|
|
28
|
-
import os
|
|
29
|
-
import sys
|
|
30
|
-
import typing
|
|
31
|
-
from unittest import TestCase
|
|
32
|
-
from unittest import TestLoader
|
|
33
|
-
from unittest import TestSuite
|
|
34
|
-
from unittest import TextTestRunner
|
|
35
|
-
|
|
36
|
-
import pytest
|
|
37
|
-
from click import echo, option
|
|
38
|
-
from click.decorators import group
|
|
39
|
-
from coverage import coverage, CoverageException
|
|
40
|
-
|
|
41
|
-
patterns = [
|
|
42
|
-
"test_*.py",
|
|
43
|
-
"*_test.py",
|
|
44
|
-
"tests_*.py",
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@group()
|
|
49
|
-
def cli_tests():
|
|
50
|
-
"""
|
|
51
|
-
Group of commands related to tests.
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@cli_tests.command("run-tests")
|
|
56
|
-
@option("-t", "--test-type", "test_type", default="unit")
|
|
57
|
-
@option("-p", "--pattern", "pattern", default="tests*.py")
|
|
58
|
-
@option("-e", "--engine", "engine", default="unittest")
|
|
59
|
-
def run_tests(test_type: str, pattern: str, engine: str) -> None:
|
|
60
|
-
"""
|
|
61
|
-
Runs tests in a specific directory using the specified engine.
|
|
62
|
-
|
|
63
|
-
:param test_type: Directory name under ./tests/ (e.g., 'unit', 'integration').
|
|
64
|
-
:param pattern: File pattern for discovery or test name pattern for filtering.
|
|
65
|
-
:param engine: Test engine to use ('unittest' or 'pytest').
|
|
66
|
-
|
|
67
|
-
File Discovery:
|
|
68
|
-
Automatically finds files matching: `test_*.py`, `*_test.py`, `tests_*.py`.
|
|
69
|
-
|
|
70
|
-
Pattern Usage:
|
|
71
|
-
- File patterns (*.py): Used for file discovery (pytest only).
|
|
72
|
-
- Test names: Used with -k option for test filtering (pytest only).
|
|
73
|
-
- Default: 'tests*.py' (backward compatibility).
|
|
74
|
-
"""
|
|
75
|
-
|
|
76
|
-
validate_engines(engine)
|
|
77
|
-
if not os.path.exists(f"./tests/{test_type}"):
|
|
78
|
-
echo(f"The directory: {test_type} does not exist under ./tests!", err=True)
|
|
79
|
-
sys.exit(1)
|
|
80
|
-
|
|
81
|
-
if test_type == "unit":
|
|
82
|
-
# Just removing verbosity from unit tests...
|
|
83
|
-
level = os.getenv("LOGGER_LEVEL_FOR_TEST", str(logging.ERROR))
|
|
84
|
-
os.environ["LOGGER_LEVEL"] = level
|
|
85
|
-
|
|
86
|
-
if engine == "pytest":
|
|
87
|
-
test_path = f"./tests/{test_type}"
|
|
88
|
-
|
|
89
|
-
# Determine if pattern is for file discovery or test filtering
|
|
90
|
-
is_file_pattern = "*" in pattern and pattern.endswith(".py")
|
|
91
|
-
|
|
92
|
-
# Find all test files using appropriate patterns
|
|
93
|
-
test_files = []
|
|
94
|
-
if is_file_pattern and pattern != "tests_*.py":
|
|
95
|
-
# Use custom file pattern for discovery
|
|
96
|
-
test_files.extend(glob.glob(f"{test_path}/{pattern}"))
|
|
97
|
-
|
|
98
|
-
else:
|
|
99
|
-
# Use default patterns for file discovery
|
|
100
|
-
for pattern_glob in patterns:
|
|
101
|
-
test_files.extend(glob.glob(f"{test_path}/{pattern_glob}"))
|
|
102
|
-
|
|
103
|
-
if not test_files:
|
|
104
|
-
echo(f"No test files found in {test_path}", err=True)
|
|
105
|
-
sys.exit(1)
|
|
106
|
-
|
|
107
|
-
# Use specific test files instead of directory discovery
|
|
108
|
-
args = test_files + ["-v"]
|
|
109
|
-
|
|
110
|
-
# If pattern is for test name filtering (not file pattern), use -k
|
|
111
|
-
if not is_file_pattern and pattern != "tests_*.py":
|
|
112
|
-
args.extend(["-k", pattern])
|
|
113
|
-
|
|
114
|
-
exit_code = pytest.main(args)
|
|
115
|
-
if exit_code != 0:
|
|
116
|
-
sys.exit(exit_code)
|
|
117
|
-
|
|
118
|
-
else:
|
|
119
|
-
# Determine if pattern is for file discovery or test filtering
|
|
120
|
-
is_file_pattern = "*" in pattern and pattern.endswith(".py")
|
|
121
|
-
|
|
122
|
-
# Use the same patterns as pytest for consistency
|
|
123
|
-
all_tests: typing.List[TestCase | TestSuite] = []
|
|
124
|
-
if is_file_pattern and pattern != "tests_*.py":
|
|
125
|
-
# Use custom file pattern for discovery
|
|
126
|
-
tests = TestLoader().discover(f"./tests/{test_type}", pattern=pattern)
|
|
127
|
-
all_tests.extend(tests)
|
|
128
|
-
else:
|
|
129
|
-
# Use default patterns for file discovery
|
|
130
|
-
for pattern_glob in patterns:
|
|
131
|
-
tests = TestLoader().discover(f"./tests/{test_type}", pattern=pattern_glob)
|
|
132
|
-
all_tests.extend(tests)
|
|
133
|
-
|
|
134
|
-
# Combine all discovered tests into a single suite
|
|
135
|
-
combined_suite = TestSuite(all_tests)
|
|
136
|
-
result = TextTestRunner(verbosity=2).run(combined_suite)
|
|
137
|
-
if not result.wasSuccessful():
|
|
138
|
-
sys.exit(1)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
@cli_tests.command("run-coverage")
|
|
142
|
-
@option("-s", "--save-report", "save_report", default=True)
|
|
143
|
-
@option("-e", "--engine", "engine", default="unittest")
|
|
144
|
-
def run_coverage(save_report: bool, engine: str) -> None:
|
|
145
|
-
"""
|
|
146
|
-
Runs all tests across all test directories and generates a coverage report.
|
|
147
|
-
|
|
148
|
-
:param save_report: Whether to save HTML and data coverage reports to disk.
|
|
149
|
-
:type save_report: bool
|
|
150
|
-
:param engine: Test engine to use ('unittest' or 'pytest').
|
|
151
|
-
:type engine: str
|
|
152
|
-
|
|
153
|
-
Coverage Analysis:
|
|
154
|
-
- Runs tests with branch coverage enabled.
|
|
155
|
-
- Analyzes all source files in current directory.
|
|
156
|
-
- Generates console report summary.
|
|
157
|
-
- Optionally saves HTML report (default: True).
|
|
158
|
-
|
|
159
|
-
File Discovery:
|
|
160
|
-
Automatically finds files matching: `test_*.py`, `*_test.py`, `tests_*.py`.
|
|
161
|
-
across all subdirectories under `./tests/`.
|
|
162
|
-
"""
|
|
163
|
-
|
|
164
|
-
validate_engines(engine)
|
|
165
|
-
os.environ["LOGGER_LEVEL"] = os.getenv("LOGGER_LEVEL_FOR_TEST", str(logging.ERROR))
|
|
166
|
-
coverage_ = coverage(branch=True, source=["."])
|
|
167
|
-
coverage_.start()
|
|
168
|
-
|
|
169
|
-
if engine == "pytest":
|
|
170
|
-
# Finding all test files using multiple patterns
|
|
171
|
-
# across all test directories...
|
|
172
|
-
test_files = []
|
|
173
|
-
for pattern_glob in patterns:
|
|
174
|
-
test_files.extend(glob.glob(f"./tests/**/{pattern_glob}", recursive=True))
|
|
175
|
-
|
|
176
|
-
if test_files:
|
|
177
|
-
exit_code = pytest.main(test_files + ["-v"])
|
|
178
|
-
else:
|
|
179
|
-
exit_code = pytest.main(["./tests", "-v"])
|
|
180
|
-
|
|
181
|
-
if exit_code != 0:
|
|
182
|
-
sys.exit(exit_code)
|
|
183
|
-
|
|
184
|
-
else:
|
|
185
|
-
all_tests: typing.List[TestCase | TestSuite] = []
|
|
186
|
-
for pattern_glob in patterns:
|
|
187
|
-
tests = TestLoader().discover("./tests", pattern=pattern_glob)
|
|
188
|
-
all_tests.extend(tests)
|
|
189
|
-
|
|
190
|
-
result = TextTestRunner(verbosity=3).run(TestSuite(all_tests))
|
|
191
|
-
if not result.wasSuccessful():
|
|
192
|
-
sys.exit(1)
|
|
193
|
-
|
|
194
|
-
coverage_.stop()
|
|
195
|
-
|
|
196
|
-
try:
|
|
197
|
-
echo("Coverage Summary:")
|
|
198
|
-
coverage_.report()
|
|
199
|
-
|
|
200
|
-
if save_report:
|
|
201
|
-
coverage_.save()
|
|
202
|
-
coverage_.html_report()
|
|
203
|
-
|
|
204
|
-
coverage_.erase()
|
|
205
|
-
|
|
206
|
-
except CoverageException as error:
|
|
207
|
-
echo(error)
|
|
208
|
-
sys.exit(1)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
def validate_engines(engine: str) -> None:
|
|
212
|
-
"""
|
|
213
|
-
Validates that the specified test engine is supported.
|
|
214
|
-
|
|
215
|
-
:param engine: The test engine name to validate.
|
|
216
|
-
:raises: SystemExit: If the engine is not in the list of valid engines.
|
|
217
|
-
|
|
218
|
-
Supported Engines:
|
|
219
|
-
- 'unittest': Python's built-in unittest framework.
|
|
220
|
-
- 'pytest': Third-party pytest framework.
|
|
221
|
-
"""
|
|
222
|
-
|
|
223
|
-
_engines = ["unittest", "pytest"]
|
|
224
|
-
if engine not in _engines:
|
|
225
|
-
echo(f"Valid engines: {_engines}", err=True)
|
|
226
|
-
sys.exit(1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|