pytest-regtest 2.2.0a1__py2.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.
@@ -0,0 +1,352 @@
1
+ Metadata-Version: 2.3
2
+ Name: pytest-regtest
3
+ Version: 2.2.0a1
4
+ Summary: pytest plugin for snapshot regression testing
5
+ Project-URL: Source, https://gitlab.com/uweschmitt/pytest-regtest
6
+ Project-URL: Documentation, https://pytest-regtest.readthedocs.org
7
+ Author-email: Uwe Schmitt <uwe.schmitt@id.ethz.ch>
8
+ License: MIT License
9
+ License-File: LICENSE.txt
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Dist: pytest>7.2
14
+ Provides-Extra: dev
15
+ Requires-Dist: black; extra == 'dev'
16
+ Requires-Dist: build; extra == 'dev'
17
+ Requires-Dist: hatchling; extra == 'dev'
18
+ Requires-Dist: numpy; extra == 'dev'
19
+ Requires-Dist: pandas; extra == 'dev'
20
+ Requires-Dist: pre-commit; extra == 'dev'
21
+ Requires-Dist: pytest-cov; extra == 'dev'
22
+ Requires-Dist: ruff; extra == 'dev'
23
+ Requires-Dist: tox; extra == 'dev'
24
+ Requires-Dist: twine; extra == 'dev'
25
+ Requires-Dist: wheel; extra == 'dev'
26
+ Description-Content-Type: text/markdown
27
+
28
+
29
+ # Home
30
+
31
+ ## About
32
+
33
+ `pytest-regtest` is a plugin for [pytest](https://pytest.org) to implement
34
+ **regression testing**.
35
+
36
+ Unlike [functional testing](https://en.wikipedia.org/wiki/Functional_testing),
37
+ [regression testing](https://en.wikipedia.org/wiki/Regression_testing)
38
+ testing does not test whether the software produces the correct
39
+ results, but whether it behaves as it did before changes were introduced.
40
+
41
+ More specifically, `pytest-regtest` provides **snapshot testing**, which
42
+ implements regression testing by recording the textual output of a test
43
+ function and comparing this recorded output to a reference output.
44
+
45
+ **Regression testing** is a common technique to implement basic testing
46
+ before refactoring legacy code that lacks a test suite.
47
+
48
+ Snapshot testing can also be used to implement tests for complex outcomes, such
49
+ as recording textual database dumps or the results of a scientific analysis
50
+ routine.
51
+
52
+
53
+ ## Installation
54
+
55
+ To install and activate this plugin execute:
56
+
57
+ $ pip install pytest-regtest
58
+
59
+ ## Basic Usage
60
+
61
+
62
+ ### Write a test
63
+
64
+ The `pytest-regtest` plugin provides multiple fixtures.
65
+ To record output, use the fixture `regtest` that works like a file handle:
66
+
67
+ ```py
68
+ def test_squares(regtest):
69
+
70
+ result = [i*i for i in range(10)]
71
+
72
+ # one way to record output:
73
+ print(result, file=regtest)
74
+
75
+ # alternative method to record output:
76
+ regtest.write("done")
77
+ ```
78
+
79
+ You can also use the `regtest_all` fixture. This enables all output to stdout to be
80
+ recorded in a test function.
81
+
82
+
83
+ ### Run the test
84
+
85
+ If you run this test script with *pytest* the first time there is no
86
+ recorded output for this test function so far and thus the test will
87
+ fail with a message including a diff:
88
+
89
+ ```
90
+ $ pytest -v test_squares.py
91
+ ============================= test session starts ==============================
92
+ platform darwin -- Python 3.11.4, pytest-8.0.0, pluggy-1.3.0 -- ...
93
+ cachedir: .pytest_cache
94
+ rootdir: ...
95
+ plugins: cov-4.1.0, pytest_regtest-2.1.0
96
+ collecting ... collected 1 item
97
+
98
+ test_squares.py::test_squares FAILED [100%]
99
+
100
+ =================================== FAILURES ===================================
101
+ _________________________________ test_squares _________________________________
102
+
103
+ regression test output not recorded yet for test_squares.py::test_squares:
104
+
105
+ [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
106
+ done
107
+ ---------------------------- pytest-regtest report -----------------------------
108
+ total number of failed regression tests: 1
109
+ =========================== short test summary info ============================
110
+ FAILED test_squares.py::test_squares
111
+ ============================== 1 failed in 0.02s ===============================
112
+ ```
113
+
114
+ This is a diff of the current output `is` to a previously recorded output
115
+ `tobe`. Since we did not record output yet, the diff contains no lines marked
116
+ `+`.
117
+
118
+
119
+ ### Reset the test
120
+
121
+ To record the current output, we run *pytest* with the *--regtest-reset*
122
+ flag:
123
+
124
+ ```
125
+ $ pytest -v --regtest-reset test_squares.py
126
+ ============================= test session starts ==============================
127
+ platform darwin -- Python 3.11.4, pytest-8.0.0, pluggy-1.3.0 -- ...
128
+ cachedir: .pytest_cache
129
+ rootdir: ...
130
+ plugins: cov-4.1.0, pytest_regtest-2.1.0
131
+ collecting ... collected 1 item
132
+
133
+ test_squares.py::test_squares RESET [100%]
134
+
135
+ ---------------------------- pytest-regtest report -----------------------------
136
+ total number of failed regression tests: 0
137
+ the following output files have been reset:
138
+ _regtest_outputs/test_squares.test_squares.out
139
+ ============================== 1 passed in 0.00s ===============================
140
+ ```
141
+
142
+ You can also see from the output that the recorded output is in the
143
+ `_regtest_outputs` folder which in the same folder as the test script.
144
+ Don't forget to commit this folder to your version control system!
145
+
146
+ ### Run the test again
147
+
148
+ When we run the test again, it succeeds:
149
+
150
+ ```
151
+ $ pytest -v test_squares.py
152
+ ============================= test session starts ==============================
153
+ platform darwin -- Python 3.11.4, pytest-8.0.0, pluggy-1.3.0 -- ...
154
+ cachedir: .pytest_cache
155
+ rootdir: ...
156
+ plugins: cov-4.1.0, pytest_regtest-2.1.0
157
+ collecting ... collected 1 item
158
+
159
+ test_squares.py::test_squares PASSED [100%]
160
+
161
+ ---------------------------- pytest-regtest report -----------------------------
162
+ total number of failed regression tests: 0
163
+ ============================== 1 passed in 0.00s ===============================
164
+ ```
165
+
166
+ ### Break the test
167
+
168
+ Let us break the test by changing the test function to compute
169
+ 11 instead of 10 square numbers:
170
+
171
+ ```py
172
+ def test_squares(regtest):
173
+
174
+ result = [i*i for i in range(11)]
175
+
176
+ # one way to record output:
177
+ print(result, file=regtest)
178
+
179
+ # alternative method to record output:
180
+ regtest.write("done")
181
+ ```
182
+
183
+ The next run of pytest delivers a nice diff of the current and expected output
184
+ from this test function:
185
+
186
+ ```
187
+ $ pytest -v test_squares.py
188
+ ============================= test session starts ==============================
189
+ platform darwin -- Python 3.11.4, pytest-8.0.0, pluggy-1.3.0 -- ...
190
+ cachedir: .pytest_cache
191
+ rootdir: ...
192
+ plugins: cov-4.1.0, pytest_regtest-2.1.0
193
+ collecting ... collected 1 item
194
+
195
+ test_squares.py::test_squares FAILED [100%]
196
+
197
+ =================================== FAILURES ===================================
198
+ _________________________________ test_squares _________________________________
199
+
200
+ regression test output differences for test_squares.py::test_squares:
201
+ (recorded output from _regtest_outputs/test_squares.test_squares.out)
202
+
203
+ > --- current
204
+ > +++ expected
205
+ > @@ -1,2 +1,2 @@
206
+ > -[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
207
+ > +[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
208
+ > done
209
+
210
+ ---------------------------- pytest-regtest report -----------------------------
211
+ total number of failed regression tests: 1
212
+ =========================== short test summary info ============================
213
+ FAILED test_squares.py::test_squares
214
+ ============================== 1 failed in 0.02s ===============================
215
+ ```
216
+
217
+
218
+ ## Other features
219
+
220
+ ### Using the `regtest` fixture as context manager
221
+
222
+ The `regtest` fixture also works as a context manager to capture
223
+ all output from the wrapped code block:
224
+
225
+ ```py
226
+ def test_squares(regtest):
227
+
228
+ result = [i*i for i in range(10)]
229
+
230
+ with regtest:
231
+ print(result)
232
+ ```
233
+
234
+ ### The `regtest_all` fixture
235
+
236
+ The `regtest_all` fixture leads to recording of all output to `stdout` in a
237
+ test function.
238
+
239
+ ```py
240
+ def test_all(regtest_all):
241
+ print("this line will be recorded.")
242
+ print("and this line also.")
243
+ ```
244
+
245
+ ### Reset individual tests
246
+
247
+ You can reset recorded output of files and functions individually as:
248
+
249
+ ```sh
250
+ $ py.test --regtest-reset test_demo.py
251
+ $ py.test --regtest-reset test_demo.py::test_squares
252
+ ```
253
+
254
+ ### Suppress diff for failed tests
255
+
256
+ To hide the diff and just show the number of lines changed, use:
257
+
258
+ ```sh
259
+ $ py.test --regtest-nodiff ...
260
+ ```
261
+
262
+
263
+ ### Show all recorded output
264
+
265
+
266
+ For complex diffs it helps to see the full recorded output also.
267
+ To enable this use:
268
+
269
+ ```sh
270
+ $ py.test --regtest-tee...
271
+ ```
272
+
273
+
274
+ ### Line endings
275
+
276
+ Per default `pytest-regtest` ignores different line endings in the output.
277
+ In case you want to disable this feature, use the `-regtest-consider-line-endings`
278
+ flag.
279
+
280
+
281
+ ## Clean indeterministic output before recording
282
+
283
+ Output can contain data which is changing from test run to test
284
+ run, e.g. paths created with the `tmpdir` fixture, hexadecimal object ids or
285
+ timestamps.
286
+
287
+ Per default the plugin helps to make output more deterministic by:
288
+
289
+ - replacing all temporary folder in the output with `<tmpdir...>` or similar markers,
290
+ depending on the origin of the temporary folder (`tempfile` module, `tmpdir` fixture,
291
+ ...)
292
+ - replacing hexadecimal numbers ` 0x...` of arbitary length by the fixed string `0x?????????`.
293
+
294
+ You can also implement your own cleanup routines as described below.
295
+
296
+ ### Register own cleanup functions
297
+
298
+ You can register own converters in `conftest.py`:
299
+
300
+ ```py
301
+ import re
302
+ import pytest_regtest
303
+
304
+ @pytest_regtest.register_converter_pre
305
+ def remove_password_lines(txt):
306
+ '''modify recorded output BEFORE the default fixes
307
+ like temp folders or hex object ids are applied'''
308
+
309
+ # remove lines with passwords:
310
+ lines = txt.splitlines(keepends=True)
311
+ lines = [l for l in lines if "password is" not in l]
312
+ return "".join(lines)
313
+
314
+ @pytest_regtest.register_converter_post
315
+ def fix_time_measurements(txt):
316
+ '''modify recorded output AFTER the default fixes
317
+ like temp folders or hex object ids are applied'''
318
+
319
+ # fix time measurements:
320
+ return re.sub(
321
+ "\d+(\.\d+)? seconds",
322
+ "<SECONDS> seconds",
323
+ txt
324
+ )
325
+ ```
326
+
327
+ If you register multiple converters they will be applied in the order of
328
+ registration.
329
+
330
+ In case your routines replace, improve or conflict with the standard cleanup converters,
331
+ you can use the flag `--regtest-disable-stdconv` to disable the default cleanup
332
+ procedure.
333
+
334
+ ## Command line options summary
335
+
336
+ These are all supported command line options:
337
+
338
+ ```
339
+ $ pytest --help
340
+ ...
341
+
342
+ regression test plugin:
343
+ --regtest-reset do not run regtest but record current output
344
+ --regtest-tee print recorded results to console too
345
+ --regtest-consider-line-endings
346
+ do not strip whitespaces at end of recorded lines
347
+ --regtest-nodiff do not show diff output for failed regresson tests
348
+ --regtest-disable-stdconv
349
+ do not apply standard output converters to clean up
350
+ indeterministic output
351
+ ...
352
+ ```
@@ -0,0 +1,12 @@
1
+ pytest_regtest/__init__.py,sha256=Y9D7u9DiyRbGMGW2X1wsl583tp_BAHTBUKJnKps8kMo,1833
2
+ pytest_regtest/numpy_handler.py,sha256=75xwG9UiFVGOp6Px0JXzr7pKxiI6cyezX3nx76h39Jo,6327
3
+ pytest_regtest/pandas_handler.py,sha256=wlCVYLQU_CJ0x6r9Nok3ToF4CXm8eydBkoil-Nu2rEk,4249
4
+ pytest_regtest/pytest_regtest.py,sha256=LmKSMVpzV7E_gh3Sm3asUqNrpmlCOsUVZ_9GoQTOgag,19105
5
+ pytest_regtest/register_third_party_handlers.py,sha256=OU0BqDBBxVPV5OidbWCd_PyI-7P3YSPhuxZhQz_6wkI,926
6
+ pytest_regtest/snapshot_handler.py,sha256=PBqpCuqIdUJrtLZ4xrLI5TstukCDxSBmQqtKxbgB204,2066
7
+ pytest_regtest/utils.py,sha256=2jYTlV_qL5hH6FCeg7T1HJJvKual-Kux2scJ9_aB1lY,811
8
+ pytest_regtest-2.2.0a1.dist-info/METADATA,sha256=0VQKTaWIgTMIePGqbIx-mjaVWfLrfJvvgpN_N56dM6w,10599
9
+ pytest_regtest-2.2.0a1.dist-info/WHEEL,sha256=fl6v0VwpzfGBVsGtkAkhILUlJxROXbA3HvRL6Fe3140,105
10
+ pytest_regtest-2.2.0a1.dist-info/entry_points.txt,sha256=4VuIhXeMGhDo0ATbaUfyjND0atofmZjV_P-o6_uEk2s,36
11
+ pytest_regtest-2.2.0a1.dist-info/licenses/LICENSE.txt,sha256=Tue36uAzpW79-9WAqzkwPhsDDVd1X-VWUmdZ0MfGYvk,1068
12
+ pytest_regtest-2.2.0a1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.25.0
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [pytest11]
2
+ regtest = pytest_regtest
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Uwe Schmitt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.