Python 3.4.1, pytest 2.6.2.
When a test fails, pytest
will routinely report what was printed to stdout by the test.
For instance this code:
def method_under_test():
print("Hallo, Welt!")
return 41
def test_result_only():
result = method_under_test()
assert result == 42
when executed as python -m pytest myfile.py
,
will report this:
================================== FAILURES ===================================
______________________________ test_result_only _______________________________
def test_result_only():
result = method_under_test()
> assert result == 42
E assert 41 == 42
pytestest.py:9: AssertionError
---------------------------- Captured stdout call -----------------------------
Hallo, Welt!
========================== 1 failed in 0.03 seconds ===========================
This is a very nice feature.
But when I use pytest's built-in capsys
fixture, like this:
def test_result_and_stdout(capsys):
result = method_under_test()
out, err = capsys.readouterr()
assert out.startswith("Hello")
assert result == 42
the report no longer contains the actual output:
================================== FAILURES ===================================
___________________________ test_result_and_stdout ____________________________
capsys = <_pytest.capture.CaptureFixture object at 0x000000000331FB70>
def test_result_and_stdout(capsys):
result = method_under_test()
out, err = capsys.readouterr()
> assert out.startswith("Hello")
E assert <built-in method startswith of str object at 0x000000000330C3B0>('Hello')
E + where <built-in method startswith of str object at 0x000000000330C3B0> = 'Hallo, Welt!\n'.startswith
pytestest.py:14: AssertionError
========================== 1 failed in 0.03 seconds ===========================
I am not sure whether this behavior is according to specification;
the pytest documentation says about readouterr
:
"After the test function finishes
the original streams will be restored."
I have tried assuming capsys
is a context manager and have
called capsys.__exit__()
just before the asserts.
This would be an ugly solution, but at least a solution if
it restored the output before my assertion.
However, this only produces
AttributeError: 'CaptureFixture' object has no attribute '__exit__'
Next I looked into the CaptureFixture
class source code
and found a promising-looking method close
(which calls
some pop_outerr_to_orig()
method),
but calling capsys.close()
in my test did not help either,
it had no obvious effect at all.
How can I get pytest to report my outputs upon failure
in a test using capsys
?
You're seeing the correct behaviour. When capsys.readouterr()
is called, it consumes the captured output. Hence, any output to stdout and stderr will no longer show up in the test report. But any new output which you create after this and do not consume will still be reported, so you can get the full output back in the report by simply writing it to the output streams once more:
def test_result_and_stdout(capsys):
result = method_under_test()
out, err = capsys.readouterr()
sys.stdout.write(out)
sys.stderr.write(err)
assert out.startswith("Hello")
assert result == 42