파이썬에서 nosetest / unittest로 출력을 어설 션하는 방법은 무엇입니까?
다음과 같은 기능에 대한 테스트를 작성하고 있습니다.
def foo():
print 'hello world!'
따라서이 함수를 테스트하고 싶을 때 코드는 다음과 같습니다.
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!'
그러나 -s 매개 변수로 nosetest를 실행하면 테스트가 중단됩니다. unittest 또는 nose 모듈로 출력을 어떻게 잡을 수 있습니까?
이 컨텍스트 관리자 를 사용하여 출력을 캡처합니다. 일시적으로 대체하여 궁극적으로 다른 답변 중 일부와 동일한 기술을 사용합니다 sys.stdout
. 모든 부기를 하나의 함수로 감싸는 컨텍스트 관리자를 선호하므로 try-finally 코드를 다시 작성할 필요가 없으며이를 위해 설정 및 해체 함수를 작성할 필요가 없습니다.
import sys
from contextlib import contextmanager
from StringIO import StringIO
@contextmanager
def captured_output():
new_out, new_err = StringIO(), StringIO()
old_out, old_err = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = new_out, new_err
yield sys.stdout, sys.stderr
finally:
sys.stdout, sys.stderr = old_out, old_err
다음과 같이 사용하십시오.
with captured_output() as (out, err):
foo()
# This can go inside or outside the `with` block
output = out.getvalue().strip()
self.assertEqual(output, 'hello world!')
또한 with
블록 을 종료하면 원래 출력 상태가 복원 되므로 첫 번째 캡처 블록과 동일한 기능으로 두 번째 캡처 블록을 설정할 수 있습니다. 이는 설정 및 해체 기능을 사용할 수 없으며 try-finally를 작성할 때 말이 많아집니다. 수동으로 차단합니다. 이 기능은 테스트의 목표가 미리 계산 된 값보다는 서로 상대적인 두 함수의 결과를 비교하는 것이었을 때 유용했습니다.
정말로이 작업을 수행하려면 테스트 기간 동안 sys.stdout을 다시 할당 할 수 있습니다.
def test_foo():
import sys
from foomodule import foo
from StringIO import StringIO
saved_stdout = sys.stdout
try:
out = StringIO()
sys.stdout = out
foo()
output = out.getvalue().strip()
assert output == 'hello world!'
finally:
sys.stdout = saved_stdout
그러나이 코드를 작성하는 경우 선택적 out
매개 변수를 foo
함수 에 전달하는 것이 좋습니다.
def foo(out=sys.stdout):
out.write("hello, world!")
그러면 테스트가 훨씬 간단합니다.
def test_foo():
from foomodule import foo
from StringIO import StringIO
out = StringIO()
foo(out=out)
output = out.getvalue().strip()
assert output == 'hello world!'
Since version 2.7, you do not need anymore to reassign sys.stdout
, this is provided through buffer
flag. Moreover, it is the default behavior of nosetest.
Here is a sample failing in non buffered context:
import sys
import unittest
def foo():
print 'hello world!'
class Case(unittest.TestCase):
def test_foo(self):
foo()
if not hasattr(sys.stdout, "getvalue"):
self.fail("need to run in buffered mode")
output = sys.stdout.getvalue().strip() # because stdout is an StringIO instance
self.assertEquals(output,'hello world!')
You can set buffer through unit2
command line flag -b
, --buffer
or in unittest.main
options. The opposite is achieved through nosetest
flag --nocapture
.
if __name__=="__main__":
assert not hasattr(sys.stdout, "getvalue")
unittest.main(module=__name__, buffer=True, exit=False)
#.
#----------------------------------------------------------------------
#Ran 1 test in 0.000s
#
#OK
assert not hasattr(sys.stdout, "getvalue")
unittest.main(module=__name__, buffer=False)
#hello world!
#F
#======================================================================
#FAIL: test_foo (__main__.Case)
#----------------------------------------------------------------------
#Traceback (most recent call last):
# File "test_stdout.py", line 15, in test_foo
# self.fail("need to run in buffered mode")
#AssertionError: need to run in buffered mode
#
#----------------------------------------------------------------------
#Ran 1 test in 0.002s
#
#FAILED (failures=1)
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.
from io import StringIO
from unittest.mock import patch
with patch('sys.stdout', new=StringIO()) as fakeOutput:
print('hello world')
self.assertEqual(fakeOutput.getvalue().strip(), 'hello world')
In python 3.5 you can use contextlib.redirect_stdout()
and StringIO()
. Here's the modification to your code
import contextlib
from io import StringIO
from foomodule import foo
def test_foo():
temp_stdout = StringIO()
with contextlib.redirect_stdout(temp_stdout):
foo()
output = temp_stdout.getvalue().strip()
assert output == 'hello world!'
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:
import sys
import unittest
from foo import foo
from StringIO import StringIO
class FooTest (unittest.TestCase):
def setUp(self):
self.held, sys.stdout = sys.stdout, StringIO()
def test_foo(self):
foo()
self.assertEqual(sys.stdout.getvalue(),'hello world!\n')
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.
def foo_msg():
return 'hello world'
def foo():
print foo_msg()
Then your test is very simple:
def test_foo_msg():
assert 'hello world' == foo_msg()
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:
with OutputBuffer() as bf:
print('hello world')
assert bf.out == 'hello world\n'
Here's the implementation:
from io import StringIO
import sys
class OutputBuffer(object):
def __init__(self):
self.stdout = StringIO()
self.stderr = StringIO()
def __enter__(self):
self.original_stdout, self.original_stderr = sys.stdout, sys.stderr
sys.stdout, sys.stderr = self.stdout, self.stderr
return self
def __exit__(self, exception_type, exception, traceback):
sys.stdout, sys.stderr = self.original_stdout, self.original_stderr
@property
def out(self):
return self.stdout.getvalue()
@property
def err(self):
return self.stderr.getvalue()
Or consider using pytest
, it has built-in support for asserting stdout and stderr. See docs
def test_myoutput(capsys): # or use "capfd" for fd-level
print("hello")
captured = capsys.readouterr()
assert captured.out == "hello\n"
print("next")
captured = capsys.readouterr()
assert captured.out == "next\n"
참고URL : https://stackoverflow.com/questions/4219717/how-to-assert-output-with-nosetest-unittest-in-python
'program story' 카테고리의 다른 글
UILabel 높이를 텍스트로 조정 (0) | 2020.08.17 |
---|---|
O (1), O (n log n) 및 O (log n) 복잡도를 갖는 알고리즘의 예 (0) | 2020.08.17 |
TabLayout을 사용할 때 탭 배경색을 어떻게 변경합니까? (0) | 2020.08.17 |
MySQL의 숨겨진 기능 (0) | 2020.08.17 |
부트 스트랩 모달이 열려 있는지 확인하는 방법으로 jquery validate를 사용할 수 있습니다. (0) | 2020.08.17 |