pytest-inline-tdd 1.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.
Files changed (46) hide show
  1. pytest_inline_tdd-1.1.0/.github/workflows/python-publish.yml +36 -0
  2. pytest_inline_tdd-1.1.0/.github/workflows/python-test.yml +40 -0
  3. pytest_inline_tdd-1.1.0/.gitignore +14 -0
  4. pytest_inline_tdd-1.1.0/LICENSE +19 -0
  5. pytest_inline_tdd-1.1.0/PKG-INFO +289 -0
  6. pytest_inline_tdd-1.1.0/README.md +235 -0
  7. pytest_inline_tdd-1.1.0/changelog +32 -0
  8. pytest_inline_tdd-1.1.0/convert_tests.py +68 -0
  9. pytest_inline_tdd-1.1.0/convert_to_tdd.py +73 -0
  10. pytest_inline_tdd-1.1.0/demo/README.md +26 -0
  11. pytest_inline_tdd-1.1.0/demo/example.py +36 -0
  12. pytest_inline_tdd-1.1.0/demo/features.py +84 -0
  13. pytest_inline_tdd-1.1.0/demo/parallel/a.py +15 -0
  14. pytest_inline_tdd-1.1.0/demo/parallel/b.py +17 -0
  15. pytest_inline_tdd-1.1.0/demo/parallel/c.py +17 -0
  16. pytest_inline_tdd-1.1.0/demo/parallel/d.py +17 -0
  17. pytest_inline_tdd-1.1.0/demo_tdd.py +45 -0
  18. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/a.py +13 -0
  19. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/a.py.backup +15 -0
  20. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/b.py +17 -0
  21. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/c.py +17 -0
  22. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/d.py +17 -0
  23. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/e.py +17 -0
  24. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/f.py +17 -0
  25. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/g.py +17 -0
  26. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/h.py +17 -0
  27. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/i.py +17 -0
  28. pytest_inline_tdd-1.1.0/integration-tests/parallelization/test_files/j.py +17 -0
  29. pytest_inline_tdd-1.1.0/integration-tests/parallelization/time-parallel-tests.sh +25 -0
  30. pytest_inline_tdd-1.1.0/integration-tests/tdd/a.py +517 -0
  31. pytest_inline_tdd-1.1.0/integration-tests/tdd/db.py +184 -0
  32. pytest_inline_tdd-1.1.0/integration-tests/tdd/np_ops.py +425 -0
  33. pytest_inline_tdd-1.1.0/prepare-conda-env.sh +60 -0
  34. pytest_inline_tdd-1.1.0/pyproject.toml +88 -0
  35. pytest_inline_tdd-1.1.0/src/inline_tdd/__about__.py +4 -0
  36. pytest_inline_tdd-1.1.0/src/inline_tdd/__init__.py +1 -0
  37. pytest_inline_tdd-1.1.0/src/inline_tdd/ast_future.py +982 -0
  38. pytest_inline_tdd-1.1.0/src/inline_tdd/inline.py +141 -0
  39. pytest_inline_tdd-1.1.0/src/inline_tdd/plugin.py +1529 -0
  40. pytest_inline_tdd-1.1.0/tdd_summary.py +36 -0
  41. pytest_inline_tdd-1.1.0/test_tdd.py +55 -0
  42. pytest_inline_tdd-1.1.0/test_tdd_verification.py +83 -0
  43. pytest_inline_tdd-1.1.0/tests/__init__.py +0 -0
  44. pytest_inline_tdd-1.1.0/tests/test_plugin.py +761 -0
  45. pytest_inline_tdd-1.1.0/tests/test_plugin.py.bak +767 -0
  46. pytest_inline_tdd-1.1.0/tox.ini +20 -0
@@ -0,0 +1,36 @@
1
+ # This workflow will upload a Python Package using Twine when a release is created
2
+ # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: Upload Python Package
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ jobs:
16
+ deploy:
17
+
18
+ runs-on: ubuntu-latest
19
+
20
+ steps:
21
+ - uses: actions/checkout@v3
22
+ - name: Set up Python
23
+ uses: actions/setup-python@v3
24
+ with:
25
+ python-version: '3.x'
26
+ - name: Install dependencies
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install build
30
+ - name: Build package
31
+ run: python -m build
32
+ - name: Publish package
33
+ uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
34
+ with:
35
+ user: __token__
36
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,40 @@
1
+ name: Python Test
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ build-linux:
10
+ runs-on: ${{ matrix.runs-on }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ['3.8', '3.9', '3.10']
15
+ runs-on: [ubuntu-latest]
16
+ include:
17
+ - python-version: '3.7'
18
+ runs-on: ubuntu-22.04
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+ - name: Install dependencies
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install -e .[dev]
30
+ - name: Test with tox
31
+ run: |
32
+ tox run
33
+ env:
34
+ TOX_GH_MAJOR_MINOR: ${{ matrix.python-version }}
35
+ - name: Test parallel execution
36
+ run: |
37
+ cd integration-tests/parallelization
38
+ bash time-parallel-tests.sh .
39
+ - name: Publish Unit Test Results
40
+ uses: EnricoMi/publish-unit-test-result-action@v2
@@ -0,0 +1,14 @@
1
+ # Temp files
2
+ *~
3
+ \#*\#
4
+ .DS_Store
5
+
6
+
7
+ build/
8
+ *.egg-info
9
+ dist/
10
+ .tox/
11
+ .pytest_cache/
12
+ __pycache__/
13
+ .vscode/
14
+ logs/
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2022-present Inline Tests Dev Team
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,289 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytest-inline-tdd
3
+ Version: 1.1.0
4
+ Summary: A pytest plugin for writing inline tests
5
+ Project-URL: Issues, https://github.com/zzctmac/inline-tdd/issues
6
+ Project-URL: Source, https://github.com/zzctmac/inline-tdd
7
+ Author-email: Zhichao Zhou <zhouzhch@shanghaitech.edu.cn>
8
+ Maintainer-email: Zhichao Zhou <zhouzhch@shanghaitech.edu.cn>
9
+ License: Copyright (c) 2022-present Inline Tests Dev Team
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+ License-File: LICENSE
29
+ Classifier: Development Status :: 4 - Beta
30
+ Classifier: Framework :: Pytest
31
+ Classifier: Intended Audience :: Developers
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Operating System :: OS Independent
34
+ Classifier: Programming Language :: Python
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3 :: Only
37
+ Classifier: Programming Language :: Python :: 3.7
38
+ Classifier: Programming Language :: Python :: 3.8
39
+ Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: Implementation :: CPython
42
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
43
+ Classifier: Topic :: Software Development :: Testing
44
+ Requires-Python: >=3.7
45
+ Requires-Dist: pytest<9.0,>=7.0
46
+ Provides-Extra: dev
47
+ Requires-Dist: black; extra == 'dev'
48
+ Requires-Dist: coverage[toml]; extra == 'dev'
49
+ Requires-Dist: hatch; extra == 'dev'
50
+ Requires-Dist: ruff; extra == 'dev'
51
+ Requires-Dist: tox; extra == 'dev'
52
+ Requires-Dist: tox-gh; extra == 'dev'
53
+ Description-Content-Type: text/markdown
54
+
55
+ # pytest-inline-tdd
56
+
57
+ A [pytest](http://pytest.org) plugin for **test-driven inline testing** — write tests *before* the code they verify, right inside your production source files.
58
+
59
+ ## Motivation
60
+
61
+ ### The Problem with Traditional Unit Tests
62
+
63
+ Traditional unit tests live in separate `test_*.py` files, isolated from production code. This creates several issues:
64
+
65
+ 1. **Distance breeds neglect** — Tests and source code reside in different files (or directories), making it easy to forget updating tests after code changes.
66
+ 2. **Coarse granularity** — Unit tests typically target entire functions or methods, lacking focused verification of individual statements within a function.
67
+ 3. **Lost context** — Reading test code requires constant switching between test files and source files, making intent harder to follow.
68
+
69
+ ### Original pytest-inline (Inline Testing)
70
+
71
+ [pytest-inline](https://github.com/EngineeringSoftware/pytest-inline) introduced the concept of **inline testing**: placing tests right next to the source code to directly verify a statement's output.
72
+
73
+ ```python
74
+ # Original inline testing: test comes AFTER the statement under test
75
+ def example(a):
76
+ b = a + 1
77
+ itest().given(a, 1).check_eq(b, 2) # Code first, test second
78
+ ```
79
+
80
+ This solves the separation problem, but it is still a **code-first, test-later** workflow.
81
+
82
+ ### pytest-inline-tdd: TDD Mode for Inline Testing
83
+
84
+ **pytest-inline-tdd** brings **Test-Driven Development (TDD)** to inline testing. The core idea:
85
+
86
+ > **Write the test (expectation) first, then write the implementation. Tests and code are tightly coupled in the same file, the same function.**
87
+
88
+ ```python
89
+ # TDD inline testing: test comes BEFORE the statement under test
90
+ from inline_tdd import itestdd
91
+
92
+ def example(a):
93
+ itestdd().given(a, 1).check_eq(b, 2) # Test first: expect b=2 when a=1
94
+ b = a + 1 # Then implement
95
+ ```
96
+
97
+ ### Key Differences from Original pytest-inline
98
+
99
+ | Feature | pytest-inline | pytest-inline-tdd |
100
+ |---------|-------------|-------------------|
101
+ | Test position | **After** the statement under test | **Before** the statement under test |
102
+ | Workflow | Code first, test later | **Test first, code later (TDD)** |
103
+ | Package name | `inline` | `inline_tdd` |
104
+ | API name | `itest()` | `itestdd()` |
105
+ | Mindset | Verify already-written code | Declare expected behavior, then implement |
106
+ | Compatibility | Supports both pre/post modes | Supports both pre (TDD) and post modes |
107
+
108
+ ## Use Cases
109
+
110
+ ### 1. Statement-Level TDD
111
+
112
+ Write your expectation for a statement first, then implement it — testing and coding happen together:
113
+
114
+ ```python
115
+ from inline_tdd import itestdd
116
+
117
+ def calculate_discount(price, rate):
118
+ itestdd().given(price, 100).given(rate, 0.2).check_eq(discount, 20.0)
119
+ discount = price * rate
120
+
121
+ itestdd().given(price, 100).given(discount, 20.0).check_eq(final, 80.0)
122
+ final = price - discount
123
+
124
+ return final
125
+ ```
126
+
127
+ ### 2. Branch Verification for Complex Control Flow
128
+
129
+ Independently verify each branch of if/elif/else, for, and while statements:
130
+
131
+ ```python
132
+ def classify(a):
133
+ itestdd().given(a, 15).check_eq(b, "large")
134
+ itestdd().given(a, 5).check_eq(b, "medium")
135
+ itestdd().given(a, -1).check_eq(b, "small")
136
+ if a > 10:
137
+ b = "large"
138
+ elif a > 0:
139
+ b = "medium"
140
+ else:
141
+ b = "small"
142
+ ```
143
+
144
+ ### 3. Step-by-Step Data Pipeline Verification
145
+
146
+ Test each transformation step in place, ensuring every stage of a pipeline behaves as expected:
147
+
148
+ ```python
149
+ import numpy as np
150
+ from inline_tdd import itestdd
151
+
152
+ def normalize(data):
153
+ itestdd().given(data, np.array([2.0, 4.0, 6.0])).check_eq(m, 4.0)
154
+ m = np.mean(data)
155
+
156
+ itestdd().given(data, np.array([2.0, 4.0, 6.0])).given(m, 4.0).check_eq(
157
+ centered.tolist(), [-2.0, 0.0, 2.0])
158
+ centered = data - m
159
+
160
+ return centered
161
+ ```
162
+
163
+ ### 4. Database Operation Verification
164
+
165
+ Inline tests work well for verifying the results of SQL queries and operations:
166
+
167
+ ```python
168
+ import sqlite3
169
+ from inline_tdd import itestdd
170
+
171
+ def count_users(conn):
172
+ itestdd().check_eq(n, 3)
173
+ n = conn.execute("SELECT COUNT(*) FROM users").fetchone()[0]
174
+ return n
175
+ ```
176
+
177
+ ### 5. Parameterized Tests
178
+
179
+ Cover multiple input-output pairs in a single statement:
180
+
181
+ ```python
182
+ def double(a):
183
+ itestdd(parameterized=True).given(a, [1, 2, 3]).check_eq(b, [2, 4, 6])
184
+ b = a * 2
185
+ ```
186
+
187
+ ## Install
188
+
189
+ ```bash
190
+ pip install pytest-inline-tdd
191
+ ```
192
+
193
+ ## Use
194
+
195
+ ```bash
196
+ # Run all inline tests in the current directory
197
+ pytest .
198
+
199
+ # Run inline tests in a specific file
200
+ pytest path/to/file.py
201
+
202
+ # Run tests with a specific tag
203
+ pytest . --inline-group tag_name
204
+ ```
205
+
206
+ ## API
207
+
208
+ ### Declaring an Inline Test
209
+
210
+ ```python
211
+ itestdd(test_name, parameterized, repeated, tag, disabled, timeout)
212
+ ```
213
+
214
+ | Parameter | Type | Default | Description |
215
+ |-----------|------|---------|-------------|
216
+ | `test_name` | str | filename + line number | Name of the test |
217
+ | `parameterized` | bool | False | Whether the test is parameterized |
218
+ | `repeated` | int | 1 | Number of times to repeat the test |
219
+ | `tag` | list | [] | Tags for grouping and filtering |
220
+ | `disabled` | bool | False | Whether the test is disabled |
221
+ | `timeout` | float | -1.0 | Timeout in seconds (-1 for no limit) |
222
+
223
+ ### Preconditions: assume
224
+
225
+ ```python
226
+ itestdd().assume(condition).given(...).check_eq(...)
227
+ ```
228
+
229
+ If `condition` is False, the test is skipped. Must appear before any `given()` calls, and only one `assume()` is allowed per test.
230
+
231
+ ### Test Inputs: given
232
+
233
+ ```python
234
+ itestdd().given(variable, value)
235
+ ```
236
+
237
+ Multiple `given()` calls can be chained. Assigns test input values to variables used in the statement under test.
238
+
239
+ ### Test Assertions: check_*
240
+
241
+ | Method | Description |
242
+ |--------|-------------|
243
+ | `check_eq(actual, expected)` | Equal |
244
+ | `check_neq(actual, expected)` | Not equal |
245
+ | `check_true(expr)` | Expression is true |
246
+ | `check_false(expr)` | Expression is false |
247
+ | `check_none(var)` | Value is None |
248
+ | `check_not_none(var)` | Value is not None |
249
+ | `check_same(a, b)` | Same object (`is`) |
250
+ | `check_not_same(a, b)` | Different objects |
251
+ | `fail()` | Force failure |
252
+
253
+ Only one check assertion is allowed per inline test.
254
+
255
+ ## Performance
256
+
257
+ Inline tests are fast — each test verifies only a single statement. In non-testing mode (i.e., normal production execution), all `itestdd()` calls behave as no-op function calls with negligible overhead.
258
+
259
+ ## Citation
260
+
261
+ This project builds on the following research:
262
+
263
+ Title: [Inline Tests](https://dl.acm.org/doi/abs/10.1145/3551349.3556952)
264
+
265
+ Authors: [Yu Liu](https://sweetstreet.github.io/), [Pengyu Nie](https://pengyunie.github.io/), [Owolabi Legunsen](https://mir.cs.illinois.edu/legunsen/), [Milos Gligoric](http://users.ece.utexas.edu/~gligoric/)
266
+
267
+ ```bibtex
268
+ @inproceedings{LiuASE22InlineTests,
269
+ title = {Inline Tests},
270
+ author = {Yu Liu and Pengyu Nie and Owolabi Legunsen and Milos Gligoric},
271
+ pages = {1--13},
272
+ booktitle = {International Conference on Automated Software Engineering},
273
+ year = {2022},
274
+ }
275
+ ```
276
+
277
+ Title: [pytest-inline](https://pengyunie.github.io/p/LiuETAL23pytest-inline.pdf)
278
+
279
+ Authors: [Yu Liu](https://sweetstreet.github.io/), [Zachary Thurston](), [Alan Han](), [Pengyu Nie](https://pengyunie.github.io/), [Milos Gligoric](http://users.ece.utexas.edu/~gligoric/), [Owolabi Legunsen](https://mir.cs.illinois.edu/legunsen/)
280
+
281
+ ```bibtex
282
+ @inproceedings{LiuICSE23PytestInline,
283
+ title = {pytest-inline: An Inline Testing Tool for Python},
284
+ author = {Yu Liu and Zachary Thurston and Alan Han and Pengyu Nie and Milos Gligoric and Owolabi Legunsen},
285
+ pages = {1--4},
286
+ booktitle = {International Conference on Software Engineering, DEMO},
287
+ year = {2023},
288
+ }
289
+ ```
@@ -0,0 +1,235 @@
1
+ # pytest-inline-tdd
2
+
3
+ A [pytest](http://pytest.org) plugin for **test-driven inline testing** — write tests *before* the code they verify, right inside your production source files.
4
+
5
+ ## Motivation
6
+
7
+ ### The Problem with Traditional Unit Tests
8
+
9
+ Traditional unit tests live in separate `test_*.py` files, isolated from production code. This creates several issues:
10
+
11
+ 1. **Distance breeds neglect** — Tests and source code reside in different files (or directories), making it easy to forget updating tests after code changes.
12
+ 2. **Coarse granularity** — Unit tests typically target entire functions or methods, lacking focused verification of individual statements within a function.
13
+ 3. **Lost context** — Reading test code requires constant switching between test files and source files, making intent harder to follow.
14
+
15
+ ### Original pytest-inline (Inline Testing)
16
+
17
+ [pytest-inline](https://github.com/EngineeringSoftware/pytest-inline) introduced the concept of **inline testing**: placing tests right next to the source code to directly verify a statement's output.
18
+
19
+ ```python
20
+ # Original inline testing: test comes AFTER the statement under test
21
+ def example(a):
22
+ b = a + 1
23
+ itest().given(a, 1).check_eq(b, 2) # Code first, test second
24
+ ```
25
+
26
+ This solves the separation problem, but it is still a **code-first, test-later** workflow.
27
+
28
+ ### pytest-inline-tdd: TDD Mode for Inline Testing
29
+
30
+ **pytest-inline-tdd** brings **Test-Driven Development (TDD)** to inline testing. The core idea:
31
+
32
+ > **Write the test (expectation) first, then write the implementation. Tests and code are tightly coupled in the same file, the same function.**
33
+
34
+ ```python
35
+ # TDD inline testing: test comes BEFORE the statement under test
36
+ from inline_tdd import itestdd
37
+
38
+ def example(a):
39
+ itestdd().given(a, 1).check_eq(b, 2) # Test first: expect b=2 when a=1
40
+ b = a + 1 # Then implement
41
+ ```
42
+
43
+ ### Key Differences from Original pytest-inline
44
+
45
+ | Feature | pytest-inline | pytest-inline-tdd |
46
+ |---------|-------------|-------------------|
47
+ | Test position | **After** the statement under test | **Before** the statement under test |
48
+ | Workflow | Code first, test later | **Test first, code later (TDD)** |
49
+ | Package name | `inline` | `inline_tdd` |
50
+ | API name | `itest()` | `itestdd()` |
51
+ | Mindset | Verify already-written code | Declare expected behavior, then implement |
52
+ | Compatibility | Supports both pre/post modes | Supports both pre (TDD) and post modes |
53
+
54
+ ## Use Cases
55
+
56
+ ### 1. Statement-Level TDD
57
+
58
+ Write your expectation for a statement first, then implement it — testing and coding happen together:
59
+
60
+ ```python
61
+ from inline_tdd import itestdd
62
+
63
+ def calculate_discount(price, rate):
64
+ itestdd().given(price, 100).given(rate, 0.2).check_eq(discount, 20.0)
65
+ discount = price * rate
66
+
67
+ itestdd().given(price, 100).given(discount, 20.0).check_eq(final, 80.0)
68
+ final = price - discount
69
+
70
+ return final
71
+ ```
72
+
73
+ ### 2. Branch Verification for Complex Control Flow
74
+
75
+ Independently verify each branch of if/elif/else, for, and while statements:
76
+
77
+ ```python
78
+ def classify(a):
79
+ itestdd().given(a, 15).check_eq(b, "large")
80
+ itestdd().given(a, 5).check_eq(b, "medium")
81
+ itestdd().given(a, -1).check_eq(b, "small")
82
+ if a > 10:
83
+ b = "large"
84
+ elif a > 0:
85
+ b = "medium"
86
+ else:
87
+ b = "small"
88
+ ```
89
+
90
+ ### 3. Step-by-Step Data Pipeline Verification
91
+
92
+ Test each transformation step in place, ensuring every stage of a pipeline behaves as expected:
93
+
94
+ ```python
95
+ import numpy as np
96
+ from inline_tdd import itestdd
97
+
98
+ def normalize(data):
99
+ itestdd().given(data, np.array([2.0, 4.0, 6.0])).check_eq(m, 4.0)
100
+ m = np.mean(data)
101
+
102
+ itestdd().given(data, np.array([2.0, 4.0, 6.0])).given(m, 4.0).check_eq(
103
+ centered.tolist(), [-2.0, 0.0, 2.0])
104
+ centered = data - m
105
+
106
+ return centered
107
+ ```
108
+
109
+ ### 4. Database Operation Verification
110
+
111
+ Inline tests work well for verifying the results of SQL queries and operations:
112
+
113
+ ```python
114
+ import sqlite3
115
+ from inline_tdd import itestdd
116
+
117
+ def count_users(conn):
118
+ itestdd().check_eq(n, 3)
119
+ n = conn.execute("SELECT COUNT(*) FROM users").fetchone()[0]
120
+ return n
121
+ ```
122
+
123
+ ### 5. Parameterized Tests
124
+
125
+ Cover multiple input-output pairs in a single statement:
126
+
127
+ ```python
128
+ def double(a):
129
+ itestdd(parameterized=True).given(a, [1, 2, 3]).check_eq(b, [2, 4, 6])
130
+ b = a * 2
131
+ ```
132
+
133
+ ## Install
134
+
135
+ ```bash
136
+ pip install pytest-inline-tdd
137
+ ```
138
+
139
+ ## Use
140
+
141
+ ```bash
142
+ # Run all inline tests in the current directory
143
+ pytest .
144
+
145
+ # Run inline tests in a specific file
146
+ pytest path/to/file.py
147
+
148
+ # Run tests with a specific tag
149
+ pytest . --inline-group tag_name
150
+ ```
151
+
152
+ ## API
153
+
154
+ ### Declaring an Inline Test
155
+
156
+ ```python
157
+ itestdd(test_name, parameterized, repeated, tag, disabled, timeout)
158
+ ```
159
+
160
+ | Parameter | Type | Default | Description |
161
+ |-----------|------|---------|-------------|
162
+ | `test_name` | str | filename + line number | Name of the test |
163
+ | `parameterized` | bool | False | Whether the test is parameterized |
164
+ | `repeated` | int | 1 | Number of times to repeat the test |
165
+ | `tag` | list | [] | Tags for grouping and filtering |
166
+ | `disabled` | bool | False | Whether the test is disabled |
167
+ | `timeout` | float | -1.0 | Timeout in seconds (-1 for no limit) |
168
+
169
+ ### Preconditions: assume
170
+
171
+ ```python
172
+ itestdd().assume(condition).given(...).check_eq(...)
173
+ ```
174
+
175
+ If `condition` is False, the test is skipped. Must appear before any `given()` calls, and only one `assume()` is allowed per test.
176
+
177
+ ### Test Inputs: given
178
+
179
+ ```python
180
+ itestdd().given(variable, value)
181
+ ```
182
+
183
+ Multiple `given()` calls can be chained. Assigns test input values to variables used in the statement under test.
184
+
185
+ ### Test Assertions: check_*
186
+
187
+ | Method | Description |
188
+ |--------|-------------|
189
+ | `check_eq(actual, expected)` | Equal |
190
+ | `check_neq(actual, expected)` | Not equal |
191
+ | `check_true(expr)` | Expression is true |
192
+ | `check_false(expr)` | Expression is false |
193
+ | `check_none(var)` | Value is None |
194
+ | `check_not_none(var)` | Value is not None |
195
+ | `check_same(a, b)` | Same object (`is`) |
196
+ | `check_not_same(a, b)` | Different objects |
197
+ | `fail()` | Force failure |
198
+
199
+ Only one check assertion is allowed per inline test.
200
+
201
+ ## Performance
202
+
203
+ Inline tests are fast — each test verifies only a single statement. In non-testing mode (i.e., normal production execution), all `itestdd()` calls behave as no-op function calls with negligible overhead.
204
+
205
+ ## Citation
206
+
207
+ This project builds on the following research:
208
+
209
+ Title: [Inline Tests](https://dl.acm.org/doi/abs/10.1145/3551349.3556952)
210
+
211
+ Authors: [Yu Liu](https://sweetstreet.github.io/), [Pengyu Nie](https://pengyunie.github.io/), [Owolabi Legunsen](https://mir.cs.illinois.edu/legunsen/), [Milos Gligoric](http://users.ece.utexas.edu/~gligoric/)
212
+
213
+ ```bibtex
214
+ @inproceedings{LiuASE22InlineTests,
215
+ title = {Inline Tests},
216
+ author = {Yu Liu and Pengyu Nie and Owolabi Legunsen and Milos Gligoric},
217
+ pages = {1--13},
218
+ booktitle = {International Conference on Automated Software Engineering},
219
+ year = {2022},
220
+ }
221
+ ```
222
+
223
+ Title: [pytest-inline](https://pengyunie.github.io/p/LiuETAL23pytest-inline.pdf)
224
+
225
+ Authors: [Yu Liu](https://sweetstreet.github.io/), [Zachary Thurston](), [Alan Han](), [Pengyu Nie](https://pengyunie.github.io/), [Milos Gligoric](http://users.ece.utexas.edu/~gligoric/), [Owolabi Legunsen](https://mir.cs.illinois.edu/legunsen/)
226
+
227
+ ```bibtex
228
+ @inproceedings{LiuICSE23PytestInline,
229
+ title = {pytest-inline: An Inline Testing Tool for Python},
230
+ author = {Yu Liu and Zachary Thurston and Alan Han and Pengyu Nie and Milos Gligoric and Owolabi Legunsen},
231
+ pages = {1--4},
232
+ booktitle = {International Conference on Software Engineering, DEMO},
233
+ year = {2023},
234
+ }
235
+ ```
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+ ## [1.1.0]
3
+ - Change: Support pytest 8
4
+
5
+ ## [1.0.5]
6
+ - Change: Remove unused code
7
+ - Change: Capture a general Exception (not limited to ImportError and ModuleNotFoundError) when attempting to import modules during collection phase
8
+
9
+ ## [1.0.4]
10
+ - Change: Update README
11
+
12
+ ## [1.0.3]
13
+ ### Changed
14
+ - Change: Use `itest` instead of `Here` for inline test constructor
15
+
16
+ ## [1.0.2]
17
+ ### Fix
18
+ - Fix: inlinetest-only skips collecting inline tests
19
+
20
+ ### Added
21
+ - Add badges in README
22
+
23
+ ## [1.0.1]
24
+ ### Added
25
+ - New README
26
+
27
+ ## [1.0.0]
28
+ ### Added
29
+
30
+ - JUnit 5 features: timeout, more types of assertions, assumptions, and running tests in order
31
+ - Option "inlinetest-only"
32
+ - Integration tests of running tests in parallel with pytest-xdist