dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[python]pytestで出力するログのレベルを設定する(pytest-capturelog)

pytest でテストを実行する際、pytest-capturelog というパッケージを入れるとログを出力することができます。
(ただし出力されるのはテストが失敗した時のみ)

このとき、debug レベル以下のログは表示したくない、といった具合に
出力するログのレベルを調整できないかと思って調べてみたらできました。のでメモ。

以下手順。

pytest, pytest-capturelog のインストール

pip でインストールするのであればこう。

$ pip install pytest
$ pip install pytest-capturelog

私は普段 zc.buildout でパッケージを管理しているので、
同じようにされている方はこちらのファイルを参考にしてください。
(といっても、普通にインストールしてるだけですが)

gae-django-template/buildout.cfg at master · zaki-yama-labs/gae-django-template · GitHub

テストを書く

はじめに用意したのはこのようなクラス。

test.py
# -*- coding: utf-8 -*-
import logging

logger = logging.getLogger(name=__name__)


def test_foo():
    logger.debug('log level: DEBUG')
    logger.info('log level: INFO')
    # ログ出力のためテストが失敗するように
    raise ValueError

これを実行すると次のようにログが出力されます。

$ py.test test.py
======================================================== test session starts ========================================================
platform darwin -- Python 2.7.5 -- py-1.4.28 -- pytest-2.7.1
rootdir: /Users/*****/pytest-capturelog-sample, inifile:
plugins: capturelog
collected 1 items

test.py F

============================================================= FAILURES ==============================================================
_____________________________________________________________ test_foo ______________________________________________________________

caplog = <pytest_capturelog.CaptureLogFuncArg object at 0x1030506d0>

    def test_foo(caplog):
        # caplog.setLevel(logging.INFO)
        logger.debug('log level: DEBUG')
        logger.info('log level: INFO')
        # ログ出力のためテストが失敗するように
>       raise ValueError
E    ValueError

test.py:12: ValueError
----------------------------------------------------------- Captured log ------------------------------------------------------------
test.py                      9 DEBUG    log level: DEBUG
test.py                     10 INFO     log level: INFO
===================================================== 1 failed in 0.01 seconds ======================================================

ログレベルを設定する

さて、本題の出力するログレベルを設定する方法ですが、
テストメソッドの引数に caplog というパラメータが渡されてくるそうです。
この caplogsetLevel というメソッドを呼び出すと、そのメソッド内でのログレベルを設定できます。

先ほどの test_foo だと、こんな感じに。

def test_foo(caplog):
    caplog.setLevel(logging.INFO)
    logger.debug('log level: DEBUG')
    logger.info('log level: INFO')
    # ログ出力のためテストが失敗するように
    raise ValueError

この状態で再度テストを実行すると...

======================================================== test session starts ========================================================
platform darwin -- Python 2.7.5 -- py-1.4.28 -- pytest-2.7.1
rootdir: /Users/********/pytest-capturelog-sample, inifile:
plugins: capturelog
collected 1 items

test.py F

============================================================= FAILURES ==============================================================
_____________________________________________________________ test_foo ______________________________________________________________

caplog = <pytest_capturelog.CaptureLogFuncArg object at 0x1030876d0>

    def test_foo(caplog):
        caplog.setLevel(logging.INFO)
        logger.debug('log level: DEBUG')
        logger.info('log level: INFO')
        # ログ出力のためテストが失敗するように
>       raise ValueError
E    ValueError

test.py:12: ValueError
----------------------------------------------------------- Captured log ------------------------------------------------------------
test.py                     10 INFO     [INFO] log
===================================================== 1 failed in 0.01 seconds ======================================================

というわけで、INFO レベル未満のログを出力しないよう設定することができました。

(おまけ)テストクラスのメソッドとして定義していたら?

pytest-capturelog のページには書いてませんが、テストクラスのメソッドであっても caplog は渡されてくるようです。
なので、

class TestClass(object):

    def test_bar(self, caplog):
        caplog.setLevel(logging.INFO)
        logger.debug('log level: DEBUG')
        logger.info('log level: INFO')
        # ログ出力のためテストが失敗するように
        raise ValueError

これで OK。