Skip to content

Commit ce342fe

Browse files
authored
Merge pull request #34 from nicoddemus/pdb-support
2 parents 96fc692 + 8dad536 commit ce342fe

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-0
lines changed

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
CHANGELOG
22
=========
33

4+
0.4.0 (2020-12-13)
5+
------------------
6+
7+
* Add support for ``--pdb`` (`#22`_).
8+
9+
.. _#22: https://github.com/pytest-dev/pytest-subtests/issues/22
10+
411
0.3.2 (2020-08-01)
512
------------------
613

README.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@ Requirements
4040
* ``Python`` >= 3.5.
4141
* ``pytest`` >= 4.4.
4242

43+
pytest 6.2+
44+
^^^^^^^^^^^
45+
46+
``pytest 6.2`` now issues a warning when internal classes are used by third-party code,
47+
which is the case for ``pytest-subtests`` which needs to use some internal classes
48+
to integrate with other pytest features (such as capturing and debugging).
49+
50+
For now users can ignore those warnings by adding this to their configuration file:
51+
52+
.. code-block:: ini
53+
54+
[pytest]
55+
filterwarnings =
56+
ignore:A private pytest class or function was used.:PytestDeprecationWarning
57+
4358
Installation
4459
------------
4560

pytest_subtests.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from _pytest.outcomes import OutcomeException
1212
from _pytest.reports import TestReport
1313
from _pytest.runner import CallInfo
14+
from _pytest.runner import check_interactive_exception
1415
from _pytest.unittest import TestCaseFunction
1516

1617
if sys.version_info[:2] < (3, 7):
@@ -80,6 +81,10 @@ def _addSubTest(self, test_case, test, exc_info):
8081
sub_report = SubTestReport.from_item_and_call(item=self, call=call_info)
8182
sub_report.context = SubTestContext(msg, dict(test.params))
8283
self.ihook.pytest_runtest_logreport(report=sub_report)
84+
if check_interactive_exception(call_info, sub_report):
85+
self.ihook.pytest_exception_interact(
86+
node=self, call=call_info, report=sub_report
87+
)
8388

8489

8590
def pytest_configure(config):
@@ -174,6 +179,11 @@ def test(self, msg=None, **kwargs):
174179
with self.suspend_capture_ctx():
175180
self.ihook.pytest_runtest_logreport(report=sub_report)
176181

182+
if check_interactive_exception(call_info, sub_report):
183+
self.ihook.pytest_exception_interact(
184+
node=self.item, call=call_info, report=sub_report
185+
)
186+
177187

178188
def make_call_info(exc_info, *, start, stop, duration, when):
179189
try:

tests/test_subtests.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33
import pytest
44

55

6+
@pytest.fixture(autouse=True)
7+
def ignore_private_class_warning(testdir):
8+
"""
9+
Make every test in this file ignore the warning about using private pytest classes;
10+
It is a risk we are willing to take in this plugin.
11+
"""
12+
testdir.makeini(
13+
"""
14+
[pytest]
15+
filterwarnings = ignore:A private pytest class
16+
"""
17+
)
18+
19+
620
@pytest.mark.parametrize("mode", ["normal", "xdist"])
721
class TestFixture:
822
"""
@@ -307,3 +321,63 @@ def test(subtests, {fixture}):
307321
result.stdout.fnmatch_lines(
308322
["*1 passed*",]
309323
)
324+
325+
326+
class TestDebugging:
327+
"""Check --pdb support for subtests fixture and TestCase.subTest."""
328+
329+
class _FakePdb:
330+
"""
331+
Fake debugger class implementation that tracks which methods were called on it.
332+
"""
333+
334+
quitting = False
335+
calls = []
336+
337+
def __init__(self, *args, **kwargs):
338+
self.calls.append("init")
339+
340+
def reset(self):
341+
self.calls.append("reset")
342+
343+
def interaction(self, *args):
344+
self.calls.append("interaction")
345+
346+
@pytest.fixture(autouse=True)
347+
def cleanup_calls(self):
348+
self._FakePdb.calls.clear()
349+
350+
def test_pdb_fixture(self, testdir, monkeypatch):
351+
testdir.makepyfile(
352+
"""
353+
def test(subtests):
354+
with subtests.test():
355+
assert 0
356+
"""
357+
)
358+
self.runpytest_and_check_pdb(testdir, monkeypatch)
359+
360+
def test_pdb_unittest(self, testdir, monkeypatch):
361+
testdir.makepyfile(
362+
"""
363+
from unittest import TestCase
364+
class Test(TestCase):
365+
def test(self):
366+
with self.subTest():
367+
assert 0
368+
"""
369+
)
370+
self.runpytest_and_check_pdb(testdir, monkeypatch)
371+
372+
def runpytest_and_check_pdb(self, testdir, monkeypatch):
373+
# Install the fake pdb implementation in pytest_subtests so we can reference
374+
# it in the command line (any module would do).
375+
import pytest_subtests
376+
377+
monkeypatch.setattr(pytest_subtests, "_CustomPdb", self._FakePdb, raising=False)
378+
result = testdir.runpytest("--pdb", "--pdbcls=pytest_subtests:_CustomPdb")
379+
380+
# Ensure pytest entered in debugging mode when encountering the failing
381+
# assert.
382+
result.stdout.fnmatch_lines("*entering PDB*")
383+
assert self._FakePdb.calls == ["init", "reset", "interaction"]

0 commit comments

Comments
 (0)