report:unittest-summary
The report:unittest-summary directive renders a unit test report as a table: a row per testsuite and
testcase, with the counts of testcases, skipped, errored, failed and passed ones, the assertions and the runtime.
The hierarchy of testsuites is shown by indentation, a status by a symbol and a CSS class.
The report is read by pyEDAA.Reports in the Any JUnit XML
format, so the reports of pytest, OSVVM and other JUnit dialects are accepted, or in
pyTooling’s own XML format. Report files are declared in conf.py,
each with an identifier the directive names in its report:unittest-summary:reportid option - so a
documentation shows as many reports as it declares.
A report can get a page per testsuite and testcase, which the table links
to and the roles tc and ts refer to.
The directive is part of pyTooling.Sphinx; it needs the extra reports.
.. report:unittest-summary::
:reportid: example
This is how the example renders, from a report of five testcases. The report is declared with pages, so every testsuite and testcase links to its page:
| Testsuite / Testcase | Testcases | Skipped | Errored | Failed | Passed | Assertions | Runtime (HH:MM:SS.sss) |
|---|---|---|---|---|---|---|---|
| ❗pytest tests | 5 | 1 | 1 | 1 | 2 | 00:00:00.290 | |
| ❗pytest | 5 | 1 | 1 | 1 | 2 | 00:00:00.290 | |
| ❗tests | 5 | 1 | 1 | 1 | 2 | 00:00:00.220 | |
| ❗unit | 5 | 1 | 1 | 1 | 2 | 00:00:00.220 | |
| ❗Arithmetic | 5 | 1 | 1 | 1 | 2 | 00:00:00.220 | |
| ✅Addition | 2 | 0 | 0 | 0 | 2 | 00:00:00.110 | |
| ✅test_Negative | 0 | 00:00:00.060 | |||||
| ✅test_Positive | 0 | 00:00:00.050 | |||||
| ❗Division | 3 | 1 | 1 | 1 | 0 | 00:00:00.110 | |
| ❌test_ByZero | 0 | 00:00:00.070 | |||||
| ⚠️test_Fraction | 0 | 00:00:00.000 | |||||
| ❗test_Rounding | 0 | 00:00:00.040 | |||||
| ❗ ERRORED | 5 | 1 | 1 | 1 | 2 | 00:00:00.290 |
The documentation’s own unit test report is rendered by this directive too, with a page per testsuite and testcase.
Installing the extra reports
The directives of domain report are registered by the extension pyTooling.Sphinx, but read the reports -
and analyze the documentation coverage - with pyEDAA.Reports, an optional dependency.
A project using a report installs it with the extra reports:
pip install pyTooling.Sphinx[reports]
Without it, the extension and every other directive work; a report directive reports on the page and in the build’s log that it needs it:
Caught ReportsPackageMissingError when reading '../report/unit/unittest.xml'.
ReportsPackageMissingError: Reading a unit test report needs 'pyEDAA.Reports', which isn't installed.
Install it with: pip install pyTooling.Sphinx[reports]
Configuration
The report files are declared in conf.py as a dictionary, keyed by the identifier a directive names in
report:unittest-summary:reportid. A path is relative to the documentation’s source directory.
pyTooling_Unittest_Testsuites→ The unit test reports, by identifier. An entry has these fields:
xml_report→ The report file, in Any JUnit XML format or pyTooling’s XML format. Required.
pages→ The document name the pages per testsuite and testcase are generated below, e.g.
unittests/src. Optional; without it, the report gets no pages.
# doc/conf.py
pyTooling_Unittest_Testsuites = {
"src": {
"xml_report": "../report/unit/unittest.xml",
"pages": "unittests/src",
}
}
The first entry is the default report of the roles tc and ts.
The configuration is checked when the build starts. A report file that doesn’t exist is logged as an error, and the entries after it aren’t read: an entry whose file is written later - e.g. by a test run in CI - goes last.
Report formats
The format of a report file is recognized by its root element:
<testsuites>or<testsuite>→ A JUnit XML file, read by pyEDAA.Reports in the Any JUnit dialect - e.g. pytest’s
--junit-xml. A testcase’s failure, error or skip message, its traceback and its captured output are shown on its page.<TestReport>→ A test report in pyTooling’s XML format, written by pyTooling’s pytest plugin with
--pytooling-xml. Its testsuites nest, and a testsuite or testcase carries a title, a summary and a description - e.g. from the markers@testsuiteand@testcaseand the doc-strings. A page shows them below its name, a link shows the title on hover.
| Testsuite / Testcase | Testcases | Skipped | Errored | Failed | Passed | Runtime (HH:MM:SS.sss) |
|---|---|---|---|---|---|---|
| ❌TestReport | 6 | 2 | 0 | 2 | 2 | 00:00:00.006 |
| ❌tests | 6 | 2 | 0 | 2 | 2 | 00:00:00.006 |
| ❌unit | 6 | 2 | 0 | 2 | 2 | 00:00:00.006 |
| ❌Arithmetic | 6 | 2 | 0 | 2 | 2 | 00:00:00.006 |
| ❌Addition | 3 | 0 | 0 | 1 | 2 | 00:00:00.005 |
| ✅Negative | 00:00:00.000 | |||||
| ✅OnePlusOne | 00:00:00.004 | |||||
| ❌OnePlusTwo | 00:00:00.000 | |||||
| ❌Division | 3 | 2 | 0 | 1 | 0 | 00:00:00.001 |
| ⚠️ByFraction | 00:00:00.000 | |||||
| ❌ByZero | 00:00:00.000 | |||||
| ⚠️RoundsUp | 00:00:00.000 | |||||
| ❌ FAILED | 6 | 2 | 0 | 2 | 2 | 00:00:00.006 |
Pages per testsuite and testcase
A report declared with the key pages gets a page per testsuite and per testcase. They are generated when the
documentation is built - no source file is written - below the document name the key states:
a testsuite’s page:
<pages>/<testsuite>/<testsuite>/..., the names of the testsuites from the report’s top down, e.g.unittests/example/pytest/tests/unit/Arithmetic;a testcase’s page:
<pages>/<testsuite>/.../<testcase>, e.g.unittests/example/pytest/tests/unit/Arithmetic/Division/test_ByZero.
Characters of a name other than letters, digits, _, - and . - e.g. the brackets of a parametrized pytest
testcase - are replaced by _. A name colliding with a sibling’s, also when differing in case only, gets the suffix
-2, -3, and so on.
A testcase’s page shows its status, duration, number of assertions (if the report has it) and its testsuite, linked; then the message and details of a failure, error or skip, and the captured standard output and standard error.
A testsuite’s page shows its status, the number of testcases per status, the duration, the number of assertions (if the report has it) and its parent testsuite; then a table of its testsuites and a table of its testcases, each linked to its page.
The title, summary and description of a pyTooling report are shown below the name, as plain text: they are doc-strings, which aren’t necessarily ReST of this documentation.
The report:unittest-summary table links every testsuite and testcase to its page; that is the entry point.
The directive lists the report’s top-level testsuites in a hidden table of contents, and a testsuite’s page lists its
testsuites and testcases, so the pages are below the summary’s document in the navigation - in the section holding
the directive. A page’s own sections - Summary, Testcases, … - aren’t listed there. A report is best shown on a
page of its own: a title, an introduction and the directive.
Hint
A testcase is as many levels below the summary’s document as the report nests testsuites - e.g. seven for
pytest/tests/unit/Arithmetic/Division/test_ByZero. A theme limits how deep its navigation goes, e.g. the
option navigation_depth of the Read the Docs theme (default 4; -1 = unlimited). pyedaa-reports
removes levels like pytest/tests/unit from a JUnit report with --pytest=reduce-depth:pytest.tests.unit.
The pages are orphans, so a report with pages, but without a summary directive, causes no warnings; its pages are reached by the roles only.
Sphinx regards the report file as the source of its pages, so a changed report regenerates its pages. As the pages are in the table of contents, LaTeX writes them too - below the summary’s section, the deepest levels as paragraphs.
Hint
A report can have thousands of testcases - pages are only generated for a report declaring pages.
Roles
The roles tc and ts refer to a testcase and a testsuite of a report with pages. They are
registered in domain report - as :report:tc: and :report:ts: - and without the domain’s prefix.
- :tc:
Refers to a testcase’s page, showing the testcase’s name, or the role’s title:
:tc:`<target>`or:tc:`title <<target>>`.The target is
[<report ID>:]<qualified name>. The qualified name is the path from the report’s top down, the names joined by.: e.g.pytest.tests.unit.Arithmetic.Division.test_ByZero. A suffix of it starting at a name -Division.test_ByZeroortest_ByZero- is accepted, if it’s unique. Without a report ID, the first report ofpyTooling_Unittest_Testsuitesis meant.A target matching nothing or several testcases is warned about.
* :tc:`test_ByZero`
* :tc:`example:Division.test_Fraction`
* :ts:`Arithmetic`
* :ts:`pytooling:Addition`
* :tc:`the skipped one <test_Fraction>`
The testsuites and testcases are objects of domain report, named <report ID>:<qualified name> in the
documentation’s inventory (objects.inv), so another documentation refers to them with intersphinx.
Options
- .. report:unittest-summary::
Renders a unit test report as a table, on landscape pages in LaTeX.
- :reportid: <identifier>
The report, as declared in
pyTooling_Unittest_Testsuites. Required.
- :testsuite-summary-name: <name>
The name of the row summarizing all testsuites, instead of the report’s own.
- :show-testcases: all | not-passed
Which testcases are listed per testsuite: all of them, or only those that didn’t pass. Default:
all.
- :no-assertions:
Leaves out the column of assertions.
- :hide-testsuite-summary:
Leaves out the row summarizing all testsuites above the testsuites.
- :class: <CSS classes>
Additional CSS classes on the table.
Styling
The table carries the classes report-unittest-table and report-unittest-<identifier>. A row carries its kind -
report-testsuitesummary, report-testsuite, report-testcase or report-summary - and its status, e.g.
testcase-failed. The stylesheet of pyTooling.Sphinx colours the rows by status; a project overrides these
rules in a stylesheet of its own, listed in html_css_files:
table.report-unittest-table > tbody > tr.testcase-skipped {
background: #eee;
}
A name is indented by its depth, two steps per level, as in the code coverage tables.
Errors
A mistake in the options, or a report that can’t be read, is reported on the page where the table would be, and in the build’s log:
Caught ReportExtensionError when checking options for directive 'unittest-summary'.
ReportExtensionError: No unit testing configuration item for 'src'.