Skip to content

Commit d952086

Browse files
committed
support --black as pytest arg
1 parent e8eedf5 commit d952086

File tree

8 files changed

+256
-3
lines changed

8 files changed

+256
-3
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
applyTo: 'python_files/tests/pytestadapter/test_discovery.py'
3+
description: 'A guide for adding new tests for pytest discovery and JSON formatting in the test_pytest_collect suite.'
4+
---
5+
6+
# How to Add New Pytest Discovery Tests
7+
8+
This guide explains how to add new tests for pytest discovery and JSON formatting in the `test_pytest_collect` suite. Follow these steps to ensure your tests are consistent and correct.
9+
10+
---
11+
12+
## 1. Add Your Test File
13+
14+
- Place your new test file/files in the appropriate subfolder under:
15+
```
16+
python_files/tests/pytestadapter/.data/
17+
```
18+
- Organize folders and files to match the structure you want to test. For example, to test nested folders, create the corresponding directory structure.
19+
- In your test file, mark each test function with a comment:
20+
```python
21+
def test_function(): # test_marker--test_function
22+
...
23+
```
24+
25+
**Root Node Matching:**
26+
27+
- The root node in your expected output must match the folder or file you pass to pytest discovery. For example, if you run discovery on a subfolder, the root `"name"`, `"path"`, and `"id_"` in your expected output should be that subfolder, not the parent `.data` folder.
28+
- Only use `.data` as the root if you are running discovery on the entire `.data` folder.
29+
30+
**Example:**
31+
If you run:
32+
33+
```python
34+
helpers.runner([os.fspath(TEST_DATA_PATH / "myfolder"), "--collect-only"])
35+
```
36+
37+
then your expected output root should be:
38+
39+
```python
40+
{
41+
"name": "myfolder",
42+
"path": os.fspath(TEST_DATA_PATH / "myfolder"),
43+
"type_": "folder",
44+
...
45+
}
46+
```
47+
48+
---
49+
50+
## 2. Update `expected_discovery_test_output.py`
51+
52+
- Open `expected_discovery_test_output.py` in the same test suite.
53+
- Add a new expected output dictionary for your test file, following the format of existing entries.
54+
- Use the helper functions and path conventions:
55+
- Use `os.fspath()` for all paths.
56+
- Use `find_test_line_number("function_name", file_path)` for the `lineno` field.
57+
- Use `get_absolute_test_id("relative_path::function_name", file_path)` for `id_` and `runID`.
58+
- Always use current path concatenation (e.g., `TEST_DATA_PATH / "your_folder" / "your_file.py"`).
59+
- Create new constants as needed to keep the code clean and maintainable.
60+
61+
**Important:**
62+
63+
- Do **not** read the entire `expected_discovery_test_output.py` file if you only need to add or reference a single constant. This file is very large; prefer searching for the relevant section or appending to the end.
64+
65+
**Example:**
66+
If you run discovery on a subfolder:
67+
68+
```python
69+
helpers.runner([os.fspath(TEST_DATA_PATH / "myfolder"), "--collect-only"])
70+
```
71+
72+
then your expected output root should be:
73+
74+
```python
75+
myfolder_path = TEST_DATA_PATH / "myfolder"
76+
my_expected_output = {
77+
"name": "myfolder",
78+
"path": os.fspath(myfolder_path),
79+
"type_": "folder",
80+
...
81+
}
82+
```
83+
84+
- Add a comment above your dictionary describing the structure, as in the existing examples.
85+
86+
---
87+
88+
## 3. Add Your Test to `test_discovery.py`
89+
90+
- In `test_discovery.py`, add your new test as a parameterized case to the main `test_pytest_collect` function. Do **not** create a standalone test function for new discovery cases.
91+
- Reference your new expected output constant from `expected_discovery_test_output.py`.
92+
93+
**Example:**
94+
95+
```python
96+
@pytest.mark.parametrize(
97+
("file", "expected_const"),
98+
[
99+
("myfolder", my_expected_output),
100+
# ... other cases ...
101+
],
102+
)
103+
def test_pytest_collect(file, expected_const):
104+
...
105+
```
106+
107+
---
108+
109+
## 4. Run and Verify
110+
111+
- Run the test suite to ensure your new test is discovered and passes.
112+
- If the test fails, check your expected output dictionary for path or structure mismatches.
113+
114+
---
115+
116+
## 5. Tips
117+
118+
- Always use the helper functions for line numbers and IDs.
119+
- Match the folder/file structure in `.data` to the expected JSON structure.
120+
- Use comments to document the expected output structure for clarity.
121+
- Ensure all `"path"` and `"id_"` fields in your expected output match exactly what pytest returns, including absolute paths and root node structure.
122+
123+
---
124+
125+
**Reference:**
126+
See `expected_discovery_test_output.py` for more examples and formatting. Use search or jump to the end of the file to avoid reading the entire file when possible.

build/test-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ pytest-describe
3939

4040
# for pytest-ruff related tests
4141
pytest-ruff
42+
pytest-black
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def add(a, b):
2+
return a + b
3+
4+
5+
def subtract(a, b):
6+
return a - b
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import pytest
2+
from app import add, subtract
3+
4+
5+
def test_add(): # test_marker--test_add
6+
assert add(2, 3) == 5
7+
assert add(-1, 1) == 0
8+
assert add(0, 0) == 0
9+
10+
11+
def test_subtract(): # test_marker--test_subtract
12+
assert subtract(5, 3) == 2
13+
assert subtract(0, 0) == 0
14+
assert subtract(-1, -1) == 0

python_files/tests/pytestadapter/expected_discovery_test_output.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,3 +1668,102 @@
16681668
],
16691669
"id_": TEST_DATA_PATH_STR,
16701670
}
1671+
1672+
# This is the expected output for the 2496-black-formatter folder when run with black plugin
1673+
# └── .data
1674+
# └── 2496-black-formatter
1675+
# └── app.py
1676+
# └── black
1677+
# └── test_app.py
1678+
# └── black
1679+
# └── test_add
1680+
# └── test_subtract
1681+
black_formatter_folder_path = TEST_DATA_PATH / "2496-black-formatter"
1682+
black_app_path = black_formatter_folder_path / "app.py"
1683+
black_test_app_path = black_formatter_folder_path / "test_app.py"
1684+
black_formatter_expected_output = {
1685+
"name": "2496-black-formatter",
1686+
"path": os.fspath(black_formatter_folder_path),
1687+
"type_": "folder",
1688+
"id_": os.fspath(black_formatter_folder_path),
1689+
"children": [
1690+
{
1691+
"name": "app.py",
1692+
"path": os.fspath(black_app_path),
1693+
"type_": "file",
1694+
"id_": os.fspath(black_app_path),
1695+
"children": [
1696+
{
1697+
"name": "black",
1698+
"path": os.fspath(black_app_path),
1699+
"lineno": "0",
1700+
"type_": "test",
1701+
"id_": get_absolute_test_id(
1702+
"2496-black-formatter/app.py::black",
1703+
black_app_path,
1704+
),
1705+
"runID": get_absolute_test_id(
1706+
"2496-black-formatter/app.py::black",
1707+
black_app_path,
1708+
),
1709+
}
1710+
],
1711+
},
1712+
{
1713+
"name": "test_app.py",
1714+
"path": os.fspath(black_test_app_path),
1715+
"type_": "file",
1716+
"id_": os.fspath(black_test_app_path),
1717+
"children": [
1718+
{
1719+
"name": "black",
1720+
"path": os.fspath(black_test_app_path),
1721+
"lineno": "0",
1722+
"type_": "test",
1723+
"id_": get_absolute_test_id(
1724+
"2496-black-formatter/test_app.py::black",
1725+
black_test_app_path,
1726+
),
1727+
"runID": get_absolute_test_id(
1728+
"2496-black-formatter/test_app.py::black",
1729+
black_test_app_path,
1730+
),
1731+
},
1732+
{
1733+
"name": "test_add",
1734+
"path": os.fspath(black_test_app_path),
1735+
"lineno": find_test_line_number(
1736+
"test_add",
1737+
black_test_app_path,
1738+
),
1739+
"type_": "test",
1740+
"id_": get_absolute_test_id(
1741+
"2496-black-formatter/test_app.py::test_add",
1742+
black_test_app_path,
1743+
),
1744+
"runID": get_absolute_test_id(
1745+
"2496-black-formatter/test_app.py::test_add",
1746+
black_test_app_path,
1747+
),
1748+
},
1749+
{
1750+
"name": "test_subtract",
1751+
"path": os.fspath(black_test_app_path),
1752+
"lineno": find_test_line_number(
1753+
"test_subtract",
1754+
black_test_app_path,
1755+
),
1756+
"type_": "test",
1757+
"id_": get_absolute_test_id(
1758+
"2496-black-formatter/test_app.py::test_subtract",
1759+
black_test_app_path,
1760+
),
1761+
"runID": get_absolute_test_id(
1762+
"2496-black-formatter/test_app.py::test_subtract",
1763+
black_test_app_path,
1764+
),
1765+
},
1766+
],
1767+
},
1768+
],
1769+
}

python_files/tests/pytestadapter/test_discovery.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ def test_parameterized_error_collect():
169169
"pytest_describe_plugin" + os.path.sep + "nested_describe.py",
170170
expected_discovery_test_output.expected_nested_describe_output,
171171
),
172+
("2496-black-formatter", expected_discovery_test_output.black_formatter_expected_output),
172173
],
173174
)
174175
def test_pytest_collect(file, expected_const):

python_files/vscode_pytest/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
from pluggy import Result
1919

2020

21-
USES_PYTEST_DESCRIBE = False
22-
2321
with contextlib.suppress(ImportError):
2422
from pytest_describe.plugin import DescribeBlock
2523

src/client/testing/testController/common/utils.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,15 @@ export function populateTestTree(
209209

210210
let range: Range | undefined;
211211
if (child.lineno) {
212-
range = new Range(new Position(Number(child.lineno) - 1, 0), new Position(Number(child.lineno), 0));
212+
// if lineno is '0'
213+
if (Number(child.lineno) === 0) {
214+
range = new Range(new Position(0, 0), new Position(0, 0));
215+
} else {
216+
range = new Range(
217+
new Position(Number(child.lineno) - 1, 0),
218+
new Position(Number(child.lineno), 0),
219+
);
220+
}
213221
}
214222
testItem.canResolveChildren = false;
215223
testItem.range = range;

0 commit comments

Comments
 (0)