Skip to content
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

Add support for --pdb in subtests #34

Merged
merged 2 commits into from
Dec 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
CHANGELOG
=========

0.4.0 (2020-12-13)
------------------

* Add support for ``--pdb`` (`#22`_).

.. _#22: https://github.com/pytest-dev/pytest-subtests/issues/22

0.3.2 (2020-08-01)
------------------

Expand Down
15 changes: 15 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ Requirements
* ``Python`` >= 3.5.
* ``pytest`` >= 4.4.

pytest 6.2+
^^^^^^^^^^^

``pytest 6.2`` now issues a warning when internal classes are used by third-party code,
which is the case for ``pytest-subtests`` which needs to use some internal classes
to integrate with other pytest features (such as capturing and debugging).

For now users can ignore those warnings by adding this to their configuration file:

.. code-block:: ini

[pytest]
filterwarnings =
ignore:A private pytest class or function was used.:PytestDeprecationWarning

Installation
------------

Expand Down
10 changes: 10 additions & 0 deletions pytest_subtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from _pytest.outcomes import OutcomeException
from _pytest.reports import TestReport
from _pytest.runner import CallInfo
from _pytest.runner import check_interactive_exception
from _pytest.unittest import TestCaseFunction

if sys.version_info[:2] < (3, 7):
Expand Down Expand Up @@ -80,6 +81,10 @@ def _addSubTest(self, test_case, test, exc_info):
sub_report = SubTestReport.from_item_and_call(item=self, call=call_info)
sub_report.context = SubTestContext(msg, dict(test.params))
self.ihook.pytest_runtest_logreport(report=sub_report)
if check_interactive_exception(call_info, sub_report):
self.ihook.pytest_exception_interact(
node=self, call=call_info, report=sub_report
)


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

if check_interactive_exception(call_info, sub_report):
self.ihook.pytest_exception_interact(
node=self.item, call=call_info, report=sub_report
)


def make_call_info(exc_info, *, start, stop, duration, when):
try:
Expand Down
74 changes: 74 additions & 0 deletions tests/test_subtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
import pytest


@pytest.fixture(autouse=True)
def ignore_private_class_warning(testdir):
"""
Make every test in this file ignore the warning about using private pytest classes;
It is a risk we are willing to take in this plugin.
"""
testdir.makeini(
"""
[pytest]
filterwarnings = ignore:A private pytest class
"""
)


@pytest.mark.parametrize("mode", ["normal", "xdist"])
class TestFixture:
"""
Expand Down Expand Up @@ -307,3 +321,63 @@ def test(subtests, {fixture}):
result.stdout.fnmatch_lines(
["*1 passed*",]
)


class TestDebugging:
"""Check --pdb support for subtests fixture and TestCase.subTest."""

class _FakePdb:
"""
Fake debugger class implementation that tracks which methods were called on it.
"""

quitting = False
calls = []

def __init__(self, *args, **kwargs):
self.calls.append("init")

def reset(self):
self.calls.append("reset")

def interaction(self, *args):
self.calls.append("interaction")

@pytest.fixture(autouse=True)
def cleanup_calls(self):
self._FakePdb.calls.clear()

def test_pdb_fixture(self, testdir, monkeypatch):
testdir.makepyfile(
"""
def test(subtests):
with subtests.test():
assert 0
"""
)
self.runpytest_and_check_pdb(testdir, monkeypatch)

def test_pdb_unittest(self, testdir, monkeypatch):
testdir.makepyfile(
"""
from unittest import TestCase
class Test(TestCase):
def test(self):
with self.subTest():
assert 0
"""
)
self.runpytest_and_check_pdb(testdir, monkeypatch)

def runpytest_and_check_pdb(self, testdir, monkeypatch):
# Install the fake pdb implementation in pytest_subtests so we can reference
# it in the command line (any module would do).
import pytest_subtests

monkeypatch.setattr(pytest_subtests, "_CustomPdb", self._FakePdb, raising=False)
result = testdir.runpytest("--pdb", "--pdbcls=pytest_subtests:_CustomPdb")

# Ensure pytest entered in debugging mode when encountering the failing
# assert.
result.stdout.fnmatch_lines("*entering PDB*")
assert self._FakePdb.calls == ["init", "reset", "interaction"]