web-dev-qa-db-ja.com

Python:コンソール印刷用のunittestの記述

関数fooはコンソールに出力します。コンソールの印刷をテストしたい。 Pythonでこれをどのように達成できますか?

この関数をテストする必要があり、returnステートメントはありません:

def foo(inStr):
   print "hi"+inStr

私のテスト:

def test_foo():
    cmdProcess = subprocess.Popen(foo("test"), stdout=subprocess.PIPE)
    cmdOut = cmdProcess.communicate()[0]
    self.assertEquals("hitest", cmdOut)
24
sudhishkr

次のように、一時的にsys.stdoutStringIOオブジェクトにリダイレクトするだけで、標準出力を簡単にキャプチャできます。

import StringIO
import sys

def foo(inStr):
    print "hi"+inStr

def test_foo():
    capturedOutput = StringIO.StringIO()          # Create StringIO object
    sys.stdout = capturedOutput                   #  and redirect stdout.
    foo('test')                                   # Call unchanged function.
    sys.stdout = sys.__stdout__                   # Reset redirect.
    print 'Captured', capturedOutput.getvalue()   # Now works as before.

test_foo()

このプログラムの出力は次のとおりです。

Captured hitest

リダイレクトが出力を正常にキャプチャし、キャプチャを開始する前の状態に出力ストリームを復元できたことを示しています。


上のコードは、Python 2.7で、質問が示すとおりです。Python 3は少し異なります:

import io
import sys

def foo(inStr):
    print ("hi"+inStr)

def test_foo():
    capturedOutput = io.StringIO()                  # Create StringIO object
    sys.stdout = capturedOutput                     #  and redirect stdout.
    foo('test')                                     # Call function.
    sys.stdout = sys.__stdout__                     # Reset redirect.
    print ('Captured', capturedOutput.getvalue())   # Now works as before.

test_foo()
39
paxdiablo

このPython 3つの答えは unittest.mock を使用します。また、再利用可能なヘルパーメソッドassert_stdoutを使用します、このヘルパーはテスト対象の機能に固有のものですが。

import io
import unittest
import unittest.mock

from .solution import fizzbuzz


class TestFizzBuzz(unittest.TestCase):

    @unittest.mock.patch('sys.stdout', new_callable=io.StringIO)
    def assert_stdout(self, n, expected_output, mock_stdout):
        fizzbuzz(n)
        self.assertEqual(mock_stdout.getvalue(), expected_output)

    def test_only_numbers(self):
        self.assert_stdout(2, '1\n2\n')

mock_stdout argは、unittest.mock.patchデコレータによってassert_stdoutメソッドに自動的に渡されることに注意してください。

汎用のTestStdoutクラス(おそらくmixin)は、原則として上記から派生できます。

Python≥3.4、 contextlib.redirect_stdout を使用している場合もありますが、それ以上の利点はないようです。 unittest.mock.patch

22
Acumenus

偶然 pytest を使用している場合、組み込みの出力キャプチャがあります。例(pytest- styleテスト):

def eggs():
    print('eggs')


def test_spam(capsys):
    eggs()
    captured = capsys.readouterr()
    assert captured.out == 'eggs\n'

unittestテストクラスでも使用できますが、たとえば自動使用フィクスチャを介してフィクスチャオブジェクトをテストクラスにパススルーする必要があります。

import unittest
import pytest


class TestSpam(unittest.TestCase):

    @pytest.fixture(autouse=True)
    def _pass_fixtures(self, capsys):
        self.capsys = capsys

    def test_eggs(self):
        eggs()
        captured = self.capsys.readouterr()
        self.assertEqual('eggs\n', captured.out)

詳細については、 テスト関数からキャプチャされた出力へのアクセス をご覧ください。

1
hoefling