Test Execution and Reporting

This module orchestrates the execution lifecycle of tests within the system and manages detailed reporting of test outcomes. It is responsible for running tests through their setup, call (execution), and teardown phases, capturing results, handling exceptions, and communicating the test progress and results to the user via terminal output and structured XML reports.


Core Concepts and Purpose

Test Execution and Reporting addresses the fundamental need to:

This module solves problems related to reliably running tests with proper isolation, reporting nuanced results, and integrating with other parts of the system that manage test discovery, fixtures, and plugins.


Module Workflow and Key Functionalities

Test Lifecycle Management

Test execution follows a structured protocol with three distinct phases:

  1. Setup: Prepares the test environment, including fixture setup and any necessary preconditions.

  2. Call: Executes the actual test function or method.

  3. Teardown: Cleans up resources and environment changes made during setup or test execution.

The `runtestprotocol` function in [src/_pytest/runner.py](/projects/286/67339) manages these phases in order for each test item:

def runtestprotocol(item: Item, log: bool = True, nextitem: Item | None = None) -> list[TestReport]:
    rep = call_and_report(item, "setup", log)
    reports = [rep]
    if rep.passed:
        if not item.config.getoption("setuponly", False):
            reports.append(call_and_report(item, "call", log))
    reports.append(call_and_report(item, "teardown", log, nextitem=nextitem))
    return reports

Exception and Outcome Handling

Reporting Infrastructure

Reporting is split into two main user-facing components:

  1. Terminal Reporting (src/_pytest/terminal.py)

    • Provides real-time feedback on test progress, including short status letters (e.g., ., F, s) and verbose output.

    • Summarizes test session start, collection progress, individual test outcomes, failures, skips, and warnings.

    • Supports configurable verbosity, coloring, and output styles.

    • Integrates with pytest's hook system to receive and display test reports (pytest_runtest_logreport) and session events.

    Example of terminal output decision logic:

    def pytest_runtest_logreport(self, report: TestReport) -> None:
        res = TestShortLogReport(*self.config.hook.pytest_report_teststatus(report=report, config=self.config))
        category, letter, word = res.category, res.letter, res.word
        self._add_stats(category, [report])
        # Writes single letter or verbose word depending on verbosity
        self._tw.write(letter, **markup)
    
  2. JUnit XML Reporting (src/_pytest/junitxml.py)

    • Generates XML reports conforming to JUnit schema for CI systems.

    • Accumulates test statistics, durations, and captures outputs and logs.

    • Writes detailed failure, skip, and error information into XML elements.

    • Supports customization of suite names, logging verbosity, and XML schema variants.

    • Registers as a pytest plugin and hooks into test report events to build the XML incrementally.

    Example of handling a test report for XML:

    def pytest_runtest_logreport(self, report: TestReport) -> None:
        if report.passed and report.when == "call":
            reporter = self._opentestcase(report)
            reporter.append_pass(report)
        elif report.failed:
            reporter = self._opentestcase(report)
            if report.when == "call":
                reporter.append_failure(report)
            else:
                reporter.append_error(report)
        elif report.skipped:
            reporter = self._opentestcase(report)
            reporter.append_skipped(report)
        self.update_testcase_duration(report)
        if report.when == "teardown":
            reporter.write_captured_output(report)
            self.finalize(report)
    

Interaction with Other System Components


Important Concepts and Design Patterns


Visual Diagram: Test Execution and Reporting Flow

sequenceDiagram
    participant Session
    participant SetupState
    participant Item
    participant Hooks as Pytest Hooks
    participant TerminalReporter
    participant JUnitXMLReporter

    Session->>SetupState: Initialize setup stack
    loop For each Test Item
        SetupState->>SetupState: Setup chain (session, module, item)
        Hooks->>Item: pytest_runtest_setup(item)
        Hooks->>Item: pytest_runtest_call(item)
        Hooks->>Item: pytest_runtest_teardown(item)

        Item->>Hooks: Generate CallInfo for each phase
        Hooks->>Hooks: pytest_runtest_makereport(call info)
        Hooks->>TerminalReporter: pytest_runtest_logreport(report)
        Hooks->>JUnitXMLReporter: pytest_runtest_logreport(report)

        SetupState->>SetupState: Teardown chain up to next item
    end
    Session->>TerminalReporter: pytest_sessionstart()
    Session->>TerminalReporter: pytest_sessionfinish()
    Session->>JUnitXMLReporter: pytest_sessionstart()
    Session->>JUnitXMLReporter: pytest_sessionfinish()

This documentation captures the core responsibilities and mechanisms of the Test Execution and Reporting module, illustrating its critical role in managing test lifecycles and delivering actionable feedback to users and CI systems.