I'm writing tests for a function like next one:
def foo():
print 'hello world!'
So when I want to test this function the code will be like this:
import sys
from foomodule import foo
def test_foo():
foo()
output = sys.stdout.getline().strip() # because stdout is an StringIO instance
assert output == 'hello world!'
But if I run nosetests with -s parameter the test crashes. How can I catch the output with unittest or nose module?
I'm only just learning Python and found myself struggling with a similar problem to the one above with unit tests for methods with output. My passing unit test for foo module above has ended up looking like this:
A lot of these answers failed for me because you can't
from StringIO import StringIO
in Python 3. Here's a minimum working snippet based on @naxa's comment and the Python Cookbook.Writing tests often shows us a better way to write our code. Similar to Shane's answer, I'd like to suggest yet another way of looking at this. Do you really want to assert that your program outputted a certain string, or just that it constructed a certain string for output? This becomes easier to test, since we can probably assume that the Python
print
statement does its job correctly.Then your test is very simple:
Of course, if you really have a need to test your program's actual output, then feel free to disregard. :)
Based on Rob Kennedy's answer, I wrote a class-based version of the context manager to buffer the output.
Usage is like:
Here's the implementation:
I use this context manager to capture output. It ultimately uses the same technique as some of the other answers by temporarily replacing
sys.stdout
. I prefer the context manager because it wraps all the bookkeeping into a single function, so I don't have to re-write any try-finally code, and I don't have to write setup and teardown functions just for this.Use it like this:
Furthermore, since the original output state is restored upon exiting the
with
block, we can set up a second capture block in the same function as the first one, which isn't possible using setup and teardown functions, and gets wordy when writing try-finally blocks manually. That ability came in handy when the goal of a test was to compare the results of two functions relative to each other rather than to some precomputed value.Or consider using
pytest
, it has built-in support for asserting stdout and stderr. See docs