記憶力が無い

プログラミングと室内園芸と何か

Pythonで標準出力をテストする

Python で標準出力される文字列のテストをすることを考えます。

class Hoge():
    def __init__(self, name):
        self.name = name

    def hoge(self):
        print(self.name)

例えば、この Hoge クラスの hoge メソッドをテストするとしましょう。

print にパッチを当てる

Python3 に標準で入っている unittest の patch を使います。

class TestHoge(TestCase):
    @patch('test_stdout.print')
    def test_hoge1(self, _print):
        hoge = Hoge('hoge')
        hoge.hoge()

        expected = call('hoge')
        actual = _print.call_args
        self.assertEqual(expected, actual)

このような形で組み込み関数の print 関数にモックオブジェクトをパッチします。 このようにすることで、標準出力そのものではありませんが、 print に渡された値を取得することが出来るので、その値をチェックします。

sys.stdout にパッチを当てる

もうちょっと直接的に標準出力の値を取得することを考えます。 先ほどは print 関数にパッチを当てましたが、今度は sys.stdout にパッチしてみましょう。

class TestHoge(TestCase):
    @patch('sys.stdout')
    def test_hoge2(self, _stdout):
        hoge = Hoge('hoge')
        hoge.hoge()

        expected = [
            call('hoge'),
            call('\n')
        ]
        actual = _stdout.write.call_args_list
        self.assertEqual(expected, actual)

実際にテストしてみると、一度の print の呼び出しで sys.stdout.write は改行の表示のために二度呼び出されていることが分かりました。

sys.stdout がどのように扱われるかは print の実装に依存しています。 今は print の実装をテストしているわけではないので、この方法で値を取得すべきではないでしょう。

test.support を使う

上で紹介した方法以外で何か良い方法がないか探したところ、下の記事を見つけました。

qiita.com

test.support モジュールに captured_stdout という標準出力をキャプチャする機能が含まれているみたいです。

このモジュールにはほかにもいろいろ使えそうな機能が含まれているようなので、機会があればちゃんと使ってみたいです。

まとめ

captured_stdout を使うと、より直接的に標準出力される値を取得出そうなことがわかりました。 でも実際のところ、一つ目に示した print にパッチを当てるだけで充分な場合が多いんじゃないかなと思います。

今回使用したコードの全体は下のリンク先に置いてます。

github.com

Copyright © 2017 ttk1