Writing a pytest function for checking the output on console (stdout)

18,854

Solution 1

Use the capfd fixture.

Example:

def test_foo(capfd):
    foo()  # Writes "Hello World!" to stdout
    out, err = capfd.readouterr()
    assert out == "Hello World!"

See: http://pytest.org/en/latest/fixture.html for more details

And see: py.test --fixtures for a list of builtin fixtures.

Your example has a few problems. Here is a corrected version:

def f(name):
    print "hello {}".format(name)


def test_f(capfd):
    f("Tom")

    out, err = capfd.readouterr()
    assert out == "hello Tom\n"

Note:

  • Do not use sys.stdout -- Use the capfd fixture as-is as provided by pytest.
  • Run the test with: py.test foo.py

Test Run Output:

$ py.test foo.py
====================================================================== test session starts ======================================================================
platform linux2 -- Python 2.7.5 -- pytest-2.4.2
plugins: flakes, cache, pep8, cov
collected 1 items 

foo.py .

=================================================================== 1 passed in 0.01 seconds ====================================================================

Also Note:

  • You do not need to run your Test Function(s) in your test modules. py.test (The CLI tool and Test Runner) does this for you.

py.test does mainly three things:

  1. Collect your tests
  2. Run your tests
  3. Display statistics and possibly errors

By default py.test looks for (configurable iirc) test_foo.py test modules and test_foo() test functions in your test modules.

Solution 2

The problem is with your explicit call of your test function at the very end of your first code snippet block:

test_add(sys.stdout)

You should not do this; it is pytest's job to call your test functions. When it does, it will recognize the name capsys (or capfd, for that matter) and automatically provide a suitable pytest-internal object for you as a call argument. (The example given in the pytest documentation is quite complete as it is.)

That object will provide the required readouterr() function. sys.stdout does not have that function, which is why your program fails.

Share:
18,854

Related videos on Youtube

brain storm
Author by

brain storm

Updated on July 03, 2022

Comments

  • brain storm
    brain storm almost 2 years

    This link gives a description how to use pytest for capturing console outputs. I tried on this following simple code, but I get error

    import sys
    import pytest
    def f(name):
        print "hello "+ name
    
    def test_add(capsys):
        f("Tom")
        out,err=capsys.readouterr()
        assert out=="hello Tom"
    
    
    test_add(sys.stdout)
    

    Output:

    python test_pytest.py 
    hello Tom
    Traceback (most recent call last):
      File "test_pytest.py", line 12, in <module>
        test_add(sys.stdout)
      File "test_pytest.py", line 8, in test_add
        out,err=capsys.readouterr()
    AttributeError: 'file' object has no attribute 'readouterr'
    

    what is wrong and what fix needed? thank you

    EDIT: As per the comment, I changed capfd, but I still get the same error

    import sys
    import pytest
    def f(name):
        print "hello "+ name
    
    def test_add(capfd):
        f("Tom")
        out,err=capfd.readouterr()
        assert out=="hello Tom"
    
    
    test_add(sys.stdout)
    
  • brain storm
    brain storm over 10 years
    this did not help. I get same error message. I pasted the code above for your reference
  • James Mills
    James Mills over 10 years
    What version of pytest are you using? Try upgrading. This works as expected and shown in all my unit tests.
  • brain storm
    brain storm over 10 years
    you never call this function test_f(capfd) in your code, is that ok?
  • James Mills
    James Mills over 10 years
    The test runner and cli tool py.test does this for you. It does three things (mainly): 1) collect all your tests 2) run all your tests and 3) produces statistics and error output
  • brain storm
    brain storm over 10 years
    how does it know which function to run for test? all functions with test_xxx?
  • James Mills
    James Mills over 10 years
    Correct. THis is configrable IRRC but by default looks for test_foo.py modules and test_foo() function in those test modules.