Pytest capsys: checking output and receiving message?

Python 3.4.1, pytest 2.6.2.

When the test fails, pytest will regularly report what was printed to stdout with the test. For example, 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 the pytest built-in capsys tool, for example:

 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 if this complies with the specification; The pytest documentation says about readouterr : "After the test function finishes, the original threads will be restored."

I tried to assume that capsys is a context manager and has called capsys.__exit__() just before the statements. That would be an ugly solution, but at least a solution if he restored the output to my approval. However, this only causes

 AttributeError: 'CaptureFixture' object has no attribute '__exit__' 

Next, I looked at the source code of the CaptureFixture class and found a promising close method (which calls some pop_outerr_to_orig() method), but the capsys.close() call did not help in my test, it had no obvious effect.

How can I get pytest to report my findings when a test fails using capsys ?

+6
source share
3 answers

You see the correct behavior, when using capsys.readouterr() you consume the captured output. Therefore, any output in stdout and stderr will no longer appear in the test report. But any new output that you create after that 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 again:

 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 
+8
source

From the documentation, the behavior seems to be correct: only after the test is completed ( test_result_and_stdout ) will the output streams be restored, and not after each readouterr call. I don't think capsys currently also supports redirection to source streams, except that it captures them, which looks like what you want.

I suggest creating a problem in the official repository and see what people say.

+3
source

How to use "startswith". You can also use the "in" keyword, for example:

  assert "Hello" in output 

This is great if you have a huge amount of data being passed to stdout, you can use "in" to check the different lines in your stdout.

 def test_result_and_stdout(capsys): result = method_under_test() out, err = capsys.readouterr() sys.stdout.write(out) sys.stderr.write(err) assert "Hello" in out assert result == 42 

You can also claim what is passed to stderr instead of stdout using:

  assert "What you are expecting" in err 

Also note that the line:

  out, err = capsys.readouterr() 

creates a snapshot of the output for both stdout and stderr, so you can say what you expect from this test.

+1
source

Source: https://habr.com/ru/post/977211/


All Articles