diff --git a/README.rst b/README.rst index f2416e2f..49eb5bda 100644 --- a/README.rst +++ b/README.rst @@ -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 ================ diff --git a/src/pytest_cov/plugin.py b/src/pytest_cov/plugin.py index 1f7c5a92..1e4b65a1 100644 --- a/src/pytest_cov/plugin.py +++ b/src/pytest_cov/plugin.py @@ -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, @@ -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: @@ -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): @@ -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', @@ -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) @@ -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 diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 6cbf3414..244ff4ce 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -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)