Is there a way get the Captured stdout call
just for a specific test without failing the test?
So lets say I have 10 tests, plus a test_summary. test_summary really just prints some kind of summary/statistics of the tests, but in order for me to get that output/printout, I have to currently fail that test intentionally. Of course this test_summary run last using pytest-ordering. But is there a better way to get that results without failing the test? Or should it not be in a test, but more in the conftest.py or something? Please advice on the best practice and how I can get this summary/results (basically a printout from a specific script I wrote)
First, to answer your exact question:
Is there a way get the
Captured stdout call
just for a specific test without failing the test?
You can add a custom section that mimics Captured stdout call
and is printed on test success. The output captured in each test is stored in the related TestReport
object and is accessed via report.capstdout
. Example impl: add the following code to a conftest.py
in your project or tests root directory:
import os
def pytest_terminal_summary(terminalreporter, exitstatus, config):
# on failures, don't add "Captured stdout call" as pytest does that already
# otherwise, the section "Captured stdout call" will be added twice
if exitstatus > 0:
return
# get all reports
reports = terminalreporter.getreports('')
# combine captured stdout of reports for tests named `<smth>::test_summary`
content = os.linesep.join(
report.capstdout for report in reports
if report.capstdout and report.nodeid.endswith("test_summary")
)
# add custom section that mimics pytest's one
if content:
terminalreporter.ensure_newline()
terminalreporter.section(
'Captured stdout call',
sep='-',
blue=True,
bold=True,
)
terminalreporter.line(content)
This will add a custom section Captured stdout call
that will only print the output captured for the test whose ID ends with test_summary
(if you have multiple test functions named test_summary
, extend the check). To distinct both sections, the custom one has a blue header; if you want it to match the original, remove color setting via blue=True
arg.
Now, to address your actual problem:
test_summary
really just prints some kind of summary/statistics of the tests
Using a test for custom reporting smells a lot like a workaround to me; why not collect the data in the tests and add a custom section printing that data afterwards? To collect the data, you can eg use the record_property
fixture:
def test_foo(record_property):
# records a key-value pair
record_property("hello", "world")
def test_bar(record_property):
record_property("spam", "eggs")
To collect and output the custom properties recorded, slightly alter the above hookimpl. The data stored via record_property
is accessible via report.user_properties
:
import os
def pytest_terminal_summary(terminalreporter, exitstatus, config):
reports = terminalreporter.getreports('')
content = os.linesep.join(
f'{key}: {value}' for report in reports
for key, value in report.user_properties
)
if content:
terminalreporter.ensure_newline()
terminalreporter.section(
'My custom summary',
sep='-',
blue=True,
bold=True
)
terminalreporter.line(content)
Running the above tests now yields:
$ pytest test_spam.py
=============================== test session starts ================================
platform linux -- Python 3.9.0, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /home/oleg.hoefling/projects/private/stackoverflow/so-64812992
plugins: metadata-1.10.0, json-report-1.2.4, cov-2.10.1, forked-1.3.0, xdist-2.1.0
collected 2 items
test_spam.py .. [100%]
-------------------------------- My custom summary ---------------------------------
hello: world
spam: eggs
================================ 2 passed in 0.01s =================================
You can use the standard pytest terminal reporter.
def test_a(request):
reporter = request.config.pluginmanager.getplugin("terminalreporter")
reporter.write_line("Hello", yellow=True)
reporter.write_line("World", red=True)
The reporter is the standard plugin available for all pytest versions that I can recall. It is not documented unfortunately while the API is pretty stable.
You can find TerminalReporter
class on pytest's github: https://github.com/pytest-dev/pytest/blob/master/src/_pytest/terminal.py
The most useful for you methods are probably ensure_line()
, write()
, flush()
and the absolute champion -- write_line()
that just do all work.
Available styles could be found at https://github.com/pytest-dev/pytest/blob/master/src/_pytest/_io/terminalwriter.py
_esctable = dict(
black=30,
red=31,
green=32,
yellow=33,
blue=34,
purple=35,
cyan=36,
white=37,
Black=40,
Red=41,
Green=42,
Yellow=43,
Blue=44,
Purple=45,
Cyan=46,
White=47,
bold=1,
light=2,
blink=5,
invert=7,
)
Lowercased styles are for the foreground, capitalized are for background.
For example, the yellow on the green text should be printed as
reporter.write_line("Text", yellow=True, Green=True)
I hope this instruction can help.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.