Skip to content

pytest Test Explorer reports a test as passed when only its first subTest passes (later subtest failures are ignored) #26181

Description

Type: Bug

Behaviour

When a unittest.TestCase test uses self.subTest(...) in a loop and runs through the pytest adapter, the Test Explorer shows the test as passed as soon as the first subtest passes. Failures in later subtests are ignored.

Running the same test from the command line (python -m pytest -v) correctly reports SUBFAIL entries and exits with a non-zero code.

Environment

  • VS Code: 1.140.0
  • Python extension (ms-python.python): 2026.6.0
  • Python: 3.14
  • pytest: 9.1.1, which supports unittest.TestCase.subTest natively. No pytest-subtests plugin is installed.
  • OS: macOS 26.4

Expected: the test is marked as failed, ideally with one result per subtest.
Actual: the test is marked as passed, and later subtest failures appear nowhere in the Test Explorer.

Root cause analysis (python_files/vscode_pytest/__init__.py)

  • pytest_report_teststatus sends one result per nodeid and skips every later report for an id already present in collected_tests_so_far.
  • With pytest ≥ 9, every subtest emits its own report with when == "call" and the same nodeid as its parent test. The first subtest's report, here a pass, is sent, and all following subtest reports, including failures, are dropped.
  • pytest_exception_interact uses the same filtering.
  • create_test_outcome ignores its subtype argument and always sets subtest=None.

Suggested fix: detect subtest reports (pytest ≥ 9 SubtestReport, or reports that carry a subtest context) and send them with a distinct id such as <nodeid> [msg] (params), filling the subtest field like the unittest adapter does. At a minimum, a failed subtest must mark its parent test as failed.

Workaround: switch to the unittest adapter (python.testing.unittestEnabled: true), which reports subtests correctly.

Steps to reproduce:

  1. Create a project with pytest 9.1.1 and enable pytest as the test runner (python.testing.pytestEnabled: true).
  2. Add the following test file:
    import unittest
    
    class TestSubtests(unittest.TestCase):
        def test_loop(self):
            for i in range(3):
                with self.subTest("case", i=i):
                    self.assertEqual(i, 0)
  3. Discover the tests, then run test_loop from the Test Explorer.
  4. Observe that test_loop is shown as passed.
  5. Run python -m pytest -v in a terminal and observe that the i=1 and i=2 subtests fail:
    [paste the output showing SUBPASS / SUBFAIL lines]
    

Diagnostic data

Output for Python in the Output panel (View→Output, change the drop-down the upper-right of the Output panel to Python)

XXX

Extension version: 2026.6.0
VS Code version: Code 1.139.1 (Universal) (04c0d99f4fb0d8afe6ce4f0c58e31e183ac3e4b1, 2026-09-25T03:40:57Z)
OS version: Darwin arm64 25.4.0
Modes:

System Info
Item Value
CPUs Apple M1 Pro (8 x 2400)
GPU Status 2d_canvas: enabled
GPU0: VENDOR= 0x106b [Google Inc. (Apple)], DEVICE=0x0000 [ANGLE (Apple, ANGLE Metal Renderer: Apple M1 Pro, Version 26.4 (Build 25E246))], DRIVER_VENDOR=Apple, DRIVER_VERSION=26.4 ACTIVE
Machine model name: MacBookPro
Machine model version: 18.3
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: enabled
multiple_raster_threads: enabled_on
opengl: enabled_on
rasterization: enabled
raw_draw: disabled_off_ok
skia_graphite: enabled_on
trees_in_viz: disabled_off
video_decode: enabled
video_encode: enabled
webgl: enabled
webgpu: enabled
webnn: disabled_off
Load (avg) 9, 11, 12
Memory (System) 16.00GB (0.09GB free)
Process Argv --crash-reporter-id 8e09e954-95f8-4519-a8a2-83eedbae3d44
Screen Reader no
VM 0%
A/B Experiments
vsliv368:30146709
vswsl492:30256859
binariesv615:30325510
nativeloc1:31344060
dwcopilot:31170013
dwoutputs:31242946
copilot_t_ci:31333650
e5gg6876:31282496
pythonrdcb7:31342333
6518g693:31463988
aj953862:31281341
b6b4d950:31327385
envsactivate1:31551504
cloudbuttont:31379625
3efgi100_wstrepl:31403338
55ia6109:31457054
ddidtcf:31399634
ec5jj548:31422691
cp_cls_t_966_ss:31526232
4je02754:31572277
8hhj4413:31478653
ge8j1254_inline_auto_hint_haiku:31490510
cp_cls_t_1081:31454832
conptydll_true:31498968
e9c30283:31461165
46204921:31447328
ei9d7968:31496641
chat:31457767
8hig5102:31480529
89g7j272:31518289
i2gc6536:31499202
52612955:31516516
ddid_c:31478207
hmra_i5g22:31518061
7df3h592:31512476
cp_cls_t_1082:31535311
logging_enabled_new:31498466
j0d79568:31499440
jb_cp_cls_t_632:31543129
56dj4588:31512888
32d76977:31512328
ha629193:31508444
a1ije391_t:31540920
jbcp_cls_pctr_t:31531130
cp_intellij_t_nes:31548657
ahp-both-windows:31556933
ihg5j128:31534457
9gg7f176:31542112
sandbox-ui-on-2:31543161
enable_editor_pane_layout:31569726
allow-none:31555437
ac562147:31564510
c7c27ce7:31554789
1h923230:31564177
treatment-23-1:31555779
unuse_dynamic_mcp:31555281
0d8dfbc3:31570291
a1hcc538:31559322
0c1h4866:31566224
session-archive:31558132
5b8j3302:31564601
autotiers:31584978
mangle-name-control:31572633
allow-signed-out:31584137
b17abb00-cfec-4134-90da-ee5e32ce4426:31589248
intellij_nes_preview_t:31580086
39a5d156:31574986
2bfb8b39:31585911
unread:31581112
links-treatment:31587702
aw-autom-on:31583758
revealsession_control_7ed7e840:31582193
usage_tips_endabled_0911:31587631
7g328426_fixed:31584544
codex-agent-host-stable-editor:31590622
54hd3363:31588611
0485115c-2712-4002-b6e9-b5d4e30fb963:31586114
sessioninlinediffenabled_disabled:31587634
welcomesignin9359t:31590011
b169b0b1-b17e-475c-9032-91b9b24dde97:31589214
ca19f5eb-b04f-4f52-8e6b-9f6927d4e0dc:31589210
deb27201-791d-4a8f-886b-37cdfe18a3df:31589213
992e63c2-18d1-4c35-8c5f-b99477991465:31589303
permission_prompt_treatment:1332566
ccr_pr_nudge_adoption:1319471
vsc_wsm_t:1340632
g03gg798:1417072
cfee5631:1379228
3aced641:1389836

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions