Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print to console in pytest?

I'm trying to use TDD (test-driven development) with pytest. pytest will not print to the console when I use print.

I am using pytest my_tests.py to run it.

The documentation seems to say that it should work by default: http://pytest.org/latest/capture.html

But:

import myapplication as tum

class TestBlogger:

    @classmethod
    def setup_class(self):
        self.user = "alice"
        self.b = tum.Blogger(self.user)
        print "This should be printed, but it won't be!"

    def test_inherit(self):
        assert issubclass(tum.Blogger, tum.Site)
        links = self.b.get_links(posts)
        print len(links)   # This won't print either.

Nothing gets printed to my standard output console (just the normal progress and how many many tests passed/failed).

And the script that I'm testing contains print:

class Blogger(Site):
    get_links(self, posts):
        print len(posts)   # It won't get printed in the test.

In unittest module, everything gets printed by default, which is exactly what I need. However, I wish to use pytest for other reasons.

Does anyone know how to make the print statements get shown?

like image 605
BBedit Avatar asked Jul 07 '14 18:07

BBedit


People also ask

Can we use print in pytest?

Allows to print extra content onto the PyTest reporting. This can be used for example to report sub-steps for long running tests, or to print debug information in your tests when you cannot debug the code.

Where does pytest print to?

By default, pytest captures the output to sys. stdout/stderr and redirects it to a temporary file.

How do I check my pytest output?

If you want to be able to see that output even if the test does not fail, then you'll want to run your pytest test with a special flag. That special flag is the -s flag. Alternatively, you could also use the --show-capture flag, which makes things a little more clear but also is a little bit longer.

How do I get a pytest report?

To generate a HTML report for a Selenium test, we have to install a plugin with the command: pip install pytest-html. To generate the report, we have to move from the current directory to the directory of the Pytest file that we want to execute. Then run the command: pytest --html=report.


8 Answers

By default, py.test captures the result of standard out so that it can control how it prints it out. If it didn't do this, it would spew out a lot of text without the context of what test printed that text.

However, if a test fails, it will include a section in the resulting report that shows what was printed to standard out in that particular test.

For example,

def test_good():
    for i in range(1000):
        print(i)

def test_bad():
    print('this should fail!')
    assert False

Results in the following output:

>>> py.test tmp.py
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py .F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
------------------------------- Captured stdout --------------------------------
this should fail!
====================== 1 failed, 1 passed in 0.04 seconds ======================

Note the Captured stdout section.

If you would like to see print statements as they are executed, you can pass the -s flag to py.test. However, note that this can sometimes be difficult to parse.

>>> py.test tmp.py -s
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py 0
1
2
3
... and so on ...
997
998
999
.this should fail!
F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
====================== 1 failed, 1 passed in 0.02 seconds ======================
like image 84
tbekolay Avatar answered Oct 03 '22 19:10

tbekolay


Short Answer

Use the -s option:

pytest -s

Detailed answer

From the docs:

During test execution any output sent to stdout and stderr is captured. If a test or a setup method fails its according captured output will usually be shown along with the failure traceback.

pytest has the option --capture=method in which method is per-test capturing method, and could be one of the following: fd, sys or no. pytest also has the option -s which is a shortcut for --capture=no, and this is the option that will allow you to see your print statements in the console.

pytest --capture=no     # show print statements in console
pytest -s               # equivalent to previous command

Setting capturing methods or disabling capturing

There are two ways in which pytest can perform capturing:

  1. file descriptor (FD) level capturing (default): All writes going to the operating system file descriptors 1 and 2 will be captured.

  2. sys level capturing: Only writes to Python files sys.stdout and sys.stderr will be captured. No capturing of writes to filedescriptors is performed.

pytest -s            # disable all capturing
pytest --capture=sys # replace sys.stdout/stderr with in-mem files
pytest --capture=fd  # also point filedescriptors 1 and 2 to temp file
like image 28
lmiguelvargasf Avatar answered Oct 03 '22 20:10

lmiguelvargasf


I needed to print important warning about skipped tests exactly when PyTest muted literally everything.

I didn't want to fail a test to send a signal, so I did a hack as follow:

def test_2_YellAboutBrokenAndMutedTests():
    import atexit
    def report():
        print C_patch.tidy_text("""
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.""")
    if sys.stdout != sys.__stdout__:
        atexit.register(report)

The atexit module allows me to print stuff after PyTest released the output streams. The output looks as follow:

============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /media/Storage/henaro/smyth/Alchemist2-git/sources/C_patch, inifile: 
collected 15 items 

test_C_patch.py .....ssss....s.

===================== 10 passed, 5 skipped in 0.15 seconds =====================
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.
~/.../sources/C_patch$

Message is printed even when PyTest is in silent mode, and is not printed if you run stuff with py.test -s, so everything is tested nicely already.

like image 24
dmitry_romanov Avatar answered Oct 03 '22 21:10

dmitry_romanov


This is the cleanest way I know to print a single statement to sys.stdout (without artificially making your test fail or enabling the -s option) - you get to see the specific output you want and nothing more:

  1. Add the in-built parameter capsys to your test function. (This means that you add capsys to the list of parameters, e.g.
def test_function(existing_parameters, capsys):
  1. In your code, simply insert:
with capsys.disabled():
   print("this output will not be captured and go straight to sys.stdout")

See https://buildmedia.readthedocs.org/media/pdf/pytest/latest/pytest.pdf (2.11 How to capture stdout/stderr output).

like image 23
Sacha Avatar answered Oct 03 '22 19:10

Sacha


According to the pytest docs, pytest --capture=sys should work. If you want to capture standard out inside a test, refer to the capsys fixture.

like image 31
Karthik Gomadam Rajagopal Avatar answered Oct 03 '22 21:10

Karthik Gomadam Rajagopal


I originally came in here to find how to make PyTest print in VSCode's console while running/debugging the unit test from there. This can be done with the following launch.json configuration. Given .venv the virtual environment folder.

    "version": "0.2.0",
    "configurations": [
        {
            "name": "PyTest",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "module": "pytest",
            "args": [
                "-sv"
            ],
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.venv",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }
    ]
}
like image 43
dummyDev Avatar answered Oct 03 '22 20:10

dummyDev


You can also set this via the Pycharm GUI: go to Run > Edit Configurations. There, select the test you want to enable print statements for and add -s to the Additional Arguments field.

I do it like this, because while I primarily use the Pycharm debugger to debug my pytest functions (i.e. via the GUI), my specific use case also requires me to know what's going on elsewhere in my code and print statements can come in handy for that.

like image 20
wlo Avatar answered Oct 03 '22 20:10

wlo


I generally use this command:-

pytest -v -rs --html=report.html --self-contained-html test_Suite.py -s

the above command also generates a report.html file where all the print statements are getting captured and saved. And the -s at the last will show the print statements into the terminal too.

like image 20
Amar Kumar Avatar answered Oct 03 '22 21:10

Amar Kumar