pytestで標準出力とログ出力をテストする

2019.11.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部の夏目です。

Lambdaでは標準出力に出力された内容がCloudWatch Logsにログとして出力されます。

標準出力の内容やログについてもテストしたいことは、まれによくあると思います。

そこで今回はpytestで標準出力やログ出力をテストしてみたいと思います。

標準出力

import sys


def put_out():
    print('aaa')
    print('bbb')


def test_pass(capfd):
    put_out()

    out, err = capfd.readouterr()
    assert out == 'aaa\nbbb\n'
    assert err is ''


def put_err():
    sys.stderr.write('aaa')
    sys.stderr.write('bbb')


def test_err(capfd):
    put_err()

    out, err = capfd.readouterr()
    assert out == ''
    assert err == 'aaabbb'

pytestの組み込みfixtureであるcapfdを使って標準出力の内容を取得する。

標準出力の他に標準エラー出力も取得できる

ログ

from logging import INFO, ERROR, getLogger

logger = getLogger('test')


def put():
    logger.debug('debug', extra={'additionaldata': 'debug'})
    logger.info('info', extra={'additionaldata': 'info'})
    logger.error('error', extra={'additionaldata': 'error'})


def test_log_01(caplog):
    caplog.set_level(ERROR)

    put()

    assert [('test', ERROR, 'error')] == caplog.record_tuples
    assert caplog.records[0].additionaldata == 'error'


def test_log_02(caplog):
    caplog.set_level(INFO)

    put()

    assert [('test', INFO, 'info'), ('test', ERROR, 'error')] == caplog.record_tuples
    assert caplog.records[0].additionaldata == 'info'
    assert caplog.records[1].additionaldata == 'error'

ログ出力を取得するのにはpytestの組み込みfixtureであるcaplogを使う。

set_levelメソッドでログレベルを設定し、record_tuplesもしくはrecordsでログの内容を取得する。

record_tuplesでは(logger_name, level, message)のタプルの配列としてデータが格納されている。

recordsではLogRecordオブジェクトの配列としてデータが格納されている。
そのため、 extraで渡した内容も取得できる。

まとめ

以上、pytestで標準出力とログのテストをする方法でした。

loggerで色々な情報を残そうとすると、複雑な処理が含まれてログ出力のテストが必要になったりして、これが非常に便利でした。