-
Notifications
You must be signed in to change notification settings - Fork 7
add pytest-subtests support #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
bfa5900
64a3236
b9ecd64
b44b935
78c2dcf
b0ed64d
1675072
5b03931
41f2cb8
f20ff8a
a5f67d1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,13 +36,17 @@ def __init__(self, config: pytest.Config) -> None: | |
| def pytest_runtestloop(self, session): | ||
| """Output the plan line first.""" | ||
| option = session.config.option | ||
| if option.tap_stream or option.tap_combined: | ||
| if (option.tap_stream or option.tap_combined) and not ( | ||
| session.config.pluginmanager.has_plugin("subtests") | ||
| ): | ||
| self._tracker.set_plan(session.testscollected) | ||
|
|
||
| @pytest.hookimpl(optionalhook=True) | ||
| def pytest_xdist_node_collection_finished(self, node, ids): | ||
| """Output the plan line first when using xdist.""" | ||
| if self._tracker.streaming or self._tracker.combined: | ||
| if (self._tracker.streaming or self._tracker.combined) and not ( | ||
| node.config.pluginmanager.has_plugin("subtests") | ||
| ): | ||
| self._tracker.set_plan(len(ids)) | ||
|
|
||
| @pytest.hookimpl() | ||
|
|
@@ -57,6 +61,10 @@ def pytest_runtest_logreport(self, report: pytest.TestReport): | |
| return | ||
|
|
||
| description = str(report.location[0]) + "::" + str(report.location[2]) | ||
| if hasattr(report, "sub_test_description"): | ||
| # Handle pytest-subtests plugin | ||
| description += report.sub_test_description() | ||
|
|
||
| testcase = report.location[0] | ||
|
|
||
| # Handle xfails first because they report in unusual ways. | ||
|
|
@@ -116,6 +124,9 @@ def pytest_runtest_logreport(self, report: pytest.TestReport): | |
| @pytest.hookimpl() | ||
| def pytest_unconfigure(self, config: pytest.Config): | ||
| """Dump the results.""" | ||
| if self._tracker.combined and config.pluginmanager.has_plugin("subtests"): | ||
| # Force Tracker to write plan at beginning of file | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we didn't write the test plan earlier, tap-py will use the number of lines to determine the test plan (combined_line_number). From my example above, that will correctly be "1..4". However, tap-py writes the test plan at the end of the file. Not sure why it was implemented that way, though it's still valid TAP formatting. To try to be as consistent as possible when subtests are vs are not used, I wanted the resulting TAP file to look similar. So by calling "set_plan" before generating the report, it ensures that "1..4" appears at the top of the file instead. |
||
| self._tracker.set_plan(self._tracker.combined_line_number) | ||
| self._tracker.generate_tap_reports() | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import pytest | ||
| from tap.tracker import ENABLE_VERSION_13 | ||
|
|
||
|
|
||
| @pytest.mark.subtests | ||
| def test_log_subtests_stream(testdir): | ||
| """Subtests are added individually to stream.""" | ||
| testdir.makepyfile( | ||
| """ | ||
| import pytest | ||
|
|
||
| def test_subtests(subtests): | ||
| for i in range(2): | ||
| with subtests.test(msg="sub_msg", i=i): | ||
| assert i % 2 == 0 | ||
| """ | ||
| ) | ||
| result = testdir.runpytest_subprocess("--tap") | ||
|
|
||
| result.stdout.fnmatch_lines( | ||
| [ | ||
| "ok 1 test_log_subtests_stream.py::test_subtests[sub_msg] (i=0)", | ||
| "not ok 2 test_log_subtests_stream.py::test_subtests[sub_msg] (i=1)", | ||
| "ok 3 test_log_subtests_stream.py::test_subtests", | ||
| "1..3", | ||
| ] | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.subtests | ||
| def test_log_subtests_combined(testdir): | ||
| """Subtests are added individually to combined.""" | ||
| testdir.makepyfile( | ||
| """ | ||
| import pytest | ||
|
|
||
| def test_subtests(subtests): | ||
| for i in range(2): | ||
| with subtests.test(msg="sub_msg", i=i): | ||
| assert i % 2 == 0 | ||
| """ | ||
| ) | ||
| testdir.runpytest_subprocess("--tap-outdir", "subtest-results", "--tap-combined") | ||
| outdir = testdir.tmpdir.join("subtest-results") | ||
| testresults = outdir.join("testresults.tap") | ||
| assert testresults.check() | ||
| actual_results = [ | ||
| line.strip() for line in testresults.readlines() if not line.startswith("#") | ||
| ] | ||
|
|
||
| expected_results = [ | ||
| "1..3", | ||
| "ok 1 test_log_subtests_combined.py::test_subtests[sub_msg] (i=0)", | ||
| "not ok 2 test_log_subtests_combined.py::test_subtests[sub_msg] (i=1)", | ||
| "ok 3 test_log_subtests_combined.py::test_subtests", | ||
| ] | ||
|
|
||
| # If the dependencies for version 13 happen to be installed, tweak the output. | ||
| if ENABLE_VERSION_13: | ||
| expected_results.insert(0, "TAP version 13") | ||
| assert actual_results == expected_results |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,30 @@ | ||
| [tox] | ||
| envlist = | ||
| subtests | ||
| coverage | ||
|
|
||
| [testenv] | ||
| deps = | ||
| pytest | ||
| commands = pytest --tap-combined {posargs} | ||
| commands = pytest -m 'not subtests' --tap-combined {posargs} | ||
|
|
||
| [testenv:subtests] | ||
| deps = | ||
| pytest | ||
| pytest-subtests | ||
| commands = pytest -m 'subtests' --tap-combined {posargs} | ||
|
|
||
| [testenv:coverage] | ||
| deps = | ||
| pytest | ||
| pytest-cov | ||
| commands = | ||
| pytest --cov=pytest_tap --cov-report xml --cov-report term | ||
| pytest -m 'not subtests' --cov=pytest_tap --cov-append --cov-report xml --cov-report term | ||
|
|
||
| [testenv:subtests-coverage] | ||
| deps = | ||
| pytest | ||
| pytest-subtests | ||
| pytest-cov | ||
| commands = | ||
| pytest -m 'subtests' --cov=pytest_tap --cov-append --cov-report xml --cov-report term |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this logic. Can you help me understand why we don't want to write the plan when the subtests plugin is available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pytest does not know about subtests at collection time. So if I have 1 test with 3 subtests, the test plan will show "1..1". But then the TAP file will contain 4 lines.