diff --git a/docs/config.rst b/docs/config.rst index fa257037..c7bef037 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -56,9 +56,9 @@ The complete list of command line options is: --cov=PATH Measure coverage for filesystem path. (multi-allowed) --cov-report=type Type of report to generate: term, term-missing, - annotate, html, xml, lcov (multi-allowed). term, term- + annotate, html, xml, json, lcov (multi-allowed). term, term- missing may be followed by ":skip-covered". annotate, - html, xml and lcov may be followed by ":DEST" where DEST + html, xml, json and lcov may be followed by ":DEST" where DEST specifies the output location. Use --cov-report= to not generate any output. --cov-config=path Config file for coverage. Default: .coveragerc diff --git a/docs/reporting.rst b/docs/reporting.rst index 69191d48..d3ae06b2 100644 --- a/docs/reporting.rst +++ b/docs/reporting.rst @@ -3,7 +3,7 @@ Reporting It is possible to generate any combination of the reports for a single test run. -The available reports are terminal (with or without missing line numbers shown), HTML, XML, LCOV and +The available reports are terminal (with or without missing line numbers shown), HTML, XML, JSON, LCOV and annotated source code. The terminal report without line numbers (default):: @@ -53,16 +53,18 @@ These four report options output to files without showing anything on the termin pytest --cov-report html --cov-report xml + --cov-report json --cov-report lcov --cov-report annotate --cov=myproj tests/ -The output location for each of these reports can be specified. The output location for the XML and LCOV +The output location for each of these reports can be specified. The output location for the XML, JSON and LCOV report is a file. Where as the output location for the HTML and annotated source code reports are directories:: pytest --cov-report html:cov_html --cov-report xml:cov.xml + --cov-report json:cov.json --cov-report lcov:cov.info --cov-report annotate:cov_annotate --cov=myproj tests/ diff --git a/src/pytest_cov/engine.py b/src/pytest_cov/engine.py index 27e1a090..f045aed5 100644 --- a/src/pytest_cov/engine.py +++ b/src/pytest_cov/engine.py @@ -196,6 +196,13 @@ def summary(self, stream): total = self.cov.xml_report(ignore_errors=True, outfile=output) stream.write('Coverage XML written to file %s\n' % (self.cov.config.xml_output if output is None else output)) + # Produce json report if wanted + if 'json' in self.cov_report: + output = self.cov_report['json'] + with _backup(self.cov, "config"): + total = self.cov.json_report(ignore_errors=True, outfile=output) + stream.write('Coverage JSON written to file %s\n' % (self.cov.config.json_output if output is None else output)) + # Produce lcov report if wanted. if 'lcov' in self.cov_report: output = self.cov_report['lcov'] diff --git a/src/pytest_cov/plugin.py b/src/pytest_cov/plugin.py index 59af4b17..036c6375 100644 --- a/src/pytest_cov/plugin.py +++ b/src/pytest_cov/plugin.py @@ -29,7 +29,7 @@ class CovReportWarning(PytestCovWarning): def validate_report(arg): - file_choices = ['annotate', 'html', 'xml', 'lcov'] + file_choices = ['annotate', 'html', 'xml', 'json', 'lcov'] term_choices = ['term', 'term-missing'] term_modifier_choices = ['skip-covered'] all_choices = term_choices + file_choices @@ -99,9 +99,9 @@ def pytest_addoption(parser): group.addoption('--cov-report', action=StoreReport, default={}, metavar='TYPE', type=validate_report, help='Type of report to generate: term, term-missing, ' - 'annotate, html, xml, lcov (multi-allowed). ' + 'annotate, html, xml, json, lcov (multi-allowed). ' 'term, term-missing may be followed by ":skip-covered". ' - 'annotate, html, xml and lcov may be followed by ":DEST" ' + 'annotate, html, xml, json and lcov may be followed by ":DEST" ' 'where DEST specifies the output location. ' 'Use --cov-report= to not generate any output.') group.addoption('--cov-config', action='store', default='.coveragerc', diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 77859bf4..5e3d0a3f 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -151,6 +151,7 @@ def test_foo(cov): PARENT_SCRIPT_RESULT = '9 * 100%' DEST_DIR = 'cov_dest' XML_REPORT_NAME = 'cov.xml' +JSON_REPORT_NAME = 'cov.json' LCOV_REPORT_NAME = 'cov.info' xdist_params = pytest.mark.parametrize('opts', [ @@ -346,6 +347,23 @@ def test_xml_output_dir(testdir): assert result.ret == 0 +def test_json_output_dir(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=json:' + JSON_REPORT_NAME, + script) + + result.stdout.fnmatch_lines([ + '*- coverage: platform *, python * -*', + 'Coverage JSON written to file ' + JSON_REPORT_NAME, + '*10 passed*', + ]) + assert testdir.tmpdir.join(JSON_REPORT_NAME).check() + assert result.ret == 0 + + @pytest.mark.skipif("coverage.version_info < (6, 3)") def test_lcov_output_dir(testdir): script = testdir.makepyfile(SCRIPT)