Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

retrieve pytest results programmatically when run via pytest.main()

Tags:

python

pytest

I'd like to run pytest and then store results and present them to users on demand (e.g. store pytest results to a db and then expose them through web service).

I could run pytest from the command line with an option to save the results report into file, then find and parse the file, but it feels silly to have the results in a (pytest) python app, then store them to a file and then instantly look for the file, and parse it back into python code for further processing.

I know I can run pytest programmatically via pytest.main(args), however, it only returns some exit code, and not details about test results. How can I retrieve the results when using pytest.main()?

I'm looking for something like:

args = ARGUMENTS
ret_code = pytest.main(args=args)  # pytest.main() as is only returns trivial return code
my_own_method_to_process(pytest.results)  # how to retrieve any kind of pytest.results object that would contain test execution results data (list of executed tests, pass fail info, etc as pytest is displaying into console or saves into file reports)

There are couple of similar questions, but always with some deviation that doesn't work for me. I simply want to run pytest from my code, and - whatever format the output would be - directly grab it and further process it.

Note: I'm in a corporate environment, where installing new packages (i.e. pytest plugins) is limited, so I'd like to achieve this without installing any other module/pytest plugin into my environment.

like image 490
stam Avatar asked Apr 28 '26 22:04

stam


1 Answers

Write a small plugin that collects and stores reports for each test. Example:

import time
import pytest


class ResultsCollector:
    def __init__(self):
        self.reports = []
        self.collected = 0
        self.exitcode = 0
        self.passed = 0
        self.failed = 0
        self.xfailed = 0
        self.skipped = 0
        self.total_duration = 0

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport(self, item, call):
        outcome = yield
        report = outcome.get_result()
        if report.when == 'call':
            self.reports.append(report)

    def pytest_collection_modifyitems(self, items):
        self.collected = len(items)

    def pytest_terminal_summary(self, terminalreporter, exitstatus):
        print(exitstatus, dir(exitstatus))
        self.exitcode = exitstatus.value
        self.passed = len(terminalreporter.stats.get('passed', []))
        self.failed = len(terminalreporter.stats.get('failed', []))
        self.xfailed = len(terminalreporter.stats.get('xfailed', []))
        self.skipped = len(terminalreporter.stats.get('skipped', []))

        self.total_duration = time.time() - terminalreporter._sessionstarttime

def run():
    collector = ResultsCollector()
    pytest.main(plugins=[collector])
    for report in collector.reports:
        print('id:', report.nodeid, 'outcome:', report.outcome)  # etc
    print('exit code:', collector.exitcode)
    print('passed:', collector.passed, 'failed:', collector.failed, 'xfailed:', collector.xfailed, 'skipped:', collector.skipped)
    print('total duration:', collector.total_duration)


if __name__ == '__main__':
    run()
like image 66
hoefling Avatar answered Apr 30 '26 12:04

hoefling



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!