feat(items): add pytest test item

Run a user pytest file as a testium item, surfacing each collected test
as a child with its own PASS/FAIL/SKIP, duration and failure message.

Mirrors the unittest item but runs pytest in a subprocess on the host
interpreter (bins.python_bin(), like py_func/lua_func) so it works across
every packaging channel. A stdlib-only pytest plugin streams collected
node-ids and per-test results over stdout via sentinels; the parent parses
them live. Params: test_file, test_method. stop_on_failure maps to -x;
disabled children are reported NORUN without running.

Wiring: TYPE_PYTEST / TYPE_PYTEST_STEP constants, test_init registration,
self-loading branch in test_set, GUI tree icon. Schema/LSP pick it up
automatically from the declarative PARAMS.

Validation: test/validation/items/pytest/ (validation venv now installs
pytest).

WIP: paused mid-feature (DESIGN.md documented; manual section pending).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 16:09:09 +02:00
parent 8c4e1b56b5
commit c77f56f2fb
10 changed files with 445 additions and 3 deletions

View File

@@ -0,0 +1 @@
no_param: Null

View File

@@ -0,0 +1,17 @@
- pytest:
name: Pytest item
test_file: {{include_directory}}/test_cases.py
key: $(test)_PASS
test_method:
- test_01_pass
- test_02_pass
- test_05_param
- pytest:
name: Pytest item
test_file: {{include_directory}}/test_cases.py
key: $(test)_FAIL
test_method:
- test_01_pass
- test_03_fail
- test_04_skip

View File

@@ -0,0 +1,28 @@
import pytest
def test_01_pass():
''' Test 01 passes '''
assert 1 + 1 == 2
def test_02_pass():
''' Test 02 passes '''
assert "a" in "abc"
def test_03_fail():
''' Test 03 fails on purpose '''
assert 1 == 2, "deliberate failure"
@pytest.mark.skip(reason="skipped on purpose")
def test_04_skip():
''' Test 04 is skipped '''
assert False
@pytest.mark.parametrize("n", [1, 2])
def test_05_param(n):
''' Test 05 is parametrised, both cases pass '''
assert n < 3