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

Implementing no_cov feature for #131 #135

Merged
merged 3 commits into from
Oct 9, 2016
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
13 changes: 13 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,19 @@ subprocess. The python used by the subprocess must have pytest-cov installed.
do normal site initialisation so that the environment variables can be detected and coverage
started.

Coverage and debuggers
----------------------

When it comes to TDD one obviously would like to debug tests. Debuggers in Python use mostly the sys.settrace function
to gain access to context. Coverage uses the same technique to get access to the lines executed. Coverage does not play
well with other tracers simultaneously running. This manifests itself in behaviour that PyCharm might not hit a
breakpoint no matter what the user does. Since it is common practice to have coverage configuration in the pytest.ini
file and pytest does not support removeopts or similar the `--no-cov` flag can disable coverage completely.

At the reporting part a warning message will show on screen

Coverage disabled via --no-cov switch!

Acknowledgements
================

Expand Down
24 changes: 24 additions & 0 deletions src/pytest_cov/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ def pytest_addoption(parser):
group.addoption('--no-cov-on-fail', action='store_true', default=False,
help='do not report coverage if test run fails, '
'default: False')
group.addoption('--no-cov', action='store_true', default=False,
help='Disable coverage report completely (useful for debuggers) '
'default: False')
group.addoption('--cov-fail-under', action='store', metavar='MIN', type=int,
help='Fail if the total coverage is less than MIN.')
group.addoption('--cov-append', action='store_true', default=False,
Expand Down Expand Up @@ -131,11 +134,16 @@ def __init__(self, options, pluginmanager, start=True):
self.cov_total = None
self.failed = False
self._started = False
self._disabled = False
self.options = options

is_dist = (getattr(options, 'numprocesses', False) or
getattr(options, 'distload', False) or
getattr(options, 'dist', 'no') != 'no')
if options.no_cov:
self._disabled = True
return

if is_dist and start:
self.start(engine.DistMaster)
elif start:
Expand All @@ -144,6 +152,7 @@ def __init__(self, options, pluginmanager, start=True):
# slave is started in pytest hook

def start(self, controller_cls, config=None, nodeid=None):

if config is None:
# fake config option for engine
class Config(object):
Expand All @@ -170,6 +179,12 @@ def _is_slave(self, session):

def pytest_sessionstart(self, session):
"""At session start determine our implementation and delegate to it."""

if self.options.no_cov:
# Coverage can be disabled because it does not cooperate with debuggers well.py
self._disabled = True
return

self.pid = os.getpid()
if self._is_slave(session):
nodeid = session.config.slaveinput.get('slaveid',
Expand Down Expand Up @@ -207,6 +222,9 @@ def _failed_cov_total(self):
def pytest_runtestloop(self, session):
yield

if self._disabled:
return

compat_session = compat.SessionWrapper(session)

self.failed = bool(compat_session.testsfailed)
Expand All @@ -226,6 +244,12 @@ def pytest_runtestloop(self, session):
compat_session.testsfailed += 1

def pytest_terminal_summary(self, terminalreporter):
if self._disabled:
msg = (
'Coverage disabled via --no-cov switch!'
)
terminalreporter.config.warn(code='COV-U1', message=msg)
return
if self.cov_controller is None:
return

Expand Down
14 changes: 14 additions & 0 deletions tests/test_pytest_cov.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,20 @@ def test_no_cov_on_fail(testdir):
result.stdout.fnmatch_lines(['*1 failed*'])


def test_no_cov(testdir):
script = testdir.makepyfile(SCRIPT)

result = testdir.runpytest('-v',
'--cov=%s' % script.dirpath(),
'--cov-report=term-missing',
'--no-cov',
'-rw',
script)

assert 'WCOV-U1 None Coverage disabled via --no-cov switch!' in result.stdout.str()
assert result.ret == 0


def test_cov_and_failure_report_on_fail(testdir):
script = testdir.makepyfile(SCRIPT + SCRIPT_FAIL)

Expand Down