diff --git a/src/pytest_cov/plugin.py b/src/pytest_cov/plugin.py index ad37e59b..d84a6dbc 100644 --- a/src/pytest_cov/plugin.py +++ b/src/pytest_cov/plugin.py @@ -41,6 +41,13 @@ def validate_report(arg): return values +def validate_fail_under(num_str): + try: + return int(num_str) + except ValueError: + return float(num_str) + + class StoreReport(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): report_type, file = values @@ -73,7 +80,8 @@ def pytest_addoption(parser): 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, + group.addoption('--cov-fail-under', action='store', metavar='MIN', + type=validate_fail_under, help='Fail if the total coverage is less than MIN.') group.addoption('--cov-append', action='store_true', default=False, help='Do not delete coverage but append to current. ' @@ -266,20 +274,18 @@ def pytest_terminal_summary(self, terminalreporter): terminalreporter.write('\n' + self.cov_report.getvalue() + '\n') if self.options.cov_fail_under is not None and self.options.cov_fail_under > 0: - if self.cov_total < self.options.cov_fail_under: - markup = {'red': True, 'bold': True} - message = ( - 'FAIL Required test coverage of %d%% not ' - 'reached. Total coverage: %.2f%%\n' - % (self.options.cov_fail_under, self.cov_total) - ) - else: - markup = {'green': True} - message = ( - 'Required test coverage of %d%% ' - 'reached. Total coverage: %.2f%%\n' - % (self.options.cov_fail_under, self.cov_total) + failed = self.cov_total < self.options.cov_fail_under + markup = {'red': True, 'bold': True} if failed else {'green': True} + message = ( + '{fail}Required test coverage of {required}% {reached}. ' + 'Total coverage: {actual:.2f}%\n' + .format( + required=self.options.cov_fail_under, + actual=self.cov_total, + fail="FAIL " if failed else "", + reached="not reached" if failed else "reached" ) + ) terminalreporter.write(message, **markup) def pytest_runtest_setup(self, item): diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 27ad610d..e745c956 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -343,6 +343,34 @@ def test_cov_min_50(testdir): ]) +def test_cov_min_float_value(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=term-missing', + '--cov-fail-under=88.88', + script) + assert result.ret == 0 + result.stdout.fnmatch_lines([ + 'Required test coverage of 88.88% reached. Total coverage: 88.89%' + ]) + + +def test_cov_min_float_value_not_reached(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=term-missing', + '--cov-fail-under=88.89', + script) + assert result.ret == 1 + result.stdout.fnmatch_lines([ + 'FAIL Required test coverage of 88.89% not reached. Total coverage: 88.89%' + ]) + + def test_cov_min_no_report(testdir): script = testdir.makepyfile(SCRIPT)