1. ホーム
  2. スクリプト・コラム
  3. パイソン

Python自動化テスト、3分間のログでバグを特定する

2022-01-26 19:12:43

I. 簡単な使い方

スタートアップの小さな一例

import logging
logging.basicConfig(level=logging.DEBUG, #set level, display according to level
    format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:% (message)s') # set output format
logging.debug('This is a debug log')
logging.info('This is a info log')
logging.warning('This is a warning log')
logging.error('This is a error log')
logging.critical('This is a critical log')


ロギングレベル

5つのログレベルが設定されており、状況に応じて異なるレベルのログが出力されます。

ロガーで設定されたレベルは、このレベル以下のログをフィルタリングします。

import logging
logging.basicConfig(level=logging.WARNING, # set level, display according to level
    format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:% (message)s') # set output format
logging.debug('This is a debug log')
logging.info('This is a info log')
logging.warning('This is a warning log')
logging.error('This is a error log')
logging.critical('This is a critical log')


2020-09-11 17:39:26,667-WARNING-This is a warning log

2020-09-11 17:39:26,669-ERROR-This is エラーログ

2020-09-11 17:39:26,669-CRITICAL-This is critical log

構成

basicConfigメソッドは、以下の設定用キーワードパラメータをサポートしています。

フォーマットルール

ログの出力形式は、以下の形式と自由に組み合わせることができます。

<イグ

共通フォーマット: %(asctime)s-[%(filename)s->line:%(lineno)d]-%(levelname)s:%(message)s

import logging
logging.basicConfig(level=logging.DEBUG, #set level, display according to level
    format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:% (message)s') # set output format
logging.debug('This is a debug log')


[DEBUG]-2020-09-11 17:36:50,125-4:This is debug log

ファイルへのログ記録

を設定するだけです。 filename パラメータ

import logging
logging.basicConfig(
    level=logging.WARNING, #set the level and display it according to the level
    filename='example.log'
    format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:% (message)s') # set output format
logging.debug('This is a debug log')
logging.info('This is a info log')
logging.warning('This is a warning log')
logging.error('This is a error log')
logging.critical('This is a critical log')


fielnameを設定した場合、ログはコンソールに出力されないことに注意してください。

II. 高度な使用法

単純なコードであればロギングをそのまま利用できますが、より深く利用するためには、ロギングをオブジェクト指向で利用する必要があります。

ロギングコンポーネント

ロギングモジュールには、以下のコンポーネントが含まれます。

ステップ

1 ロガーの作成

import logging
# The first step creates a logger, which is used to generate logs
logger = logging.getLogger('%s_log' % __name__)
logger.setLevel(logging.DEBUG) # Set the logging level


getLogger メソッドでロガーを作成することができます。名前を指定しないと、ルートロガーが返されることに注意してください。

setLevelでロガーのレベルを設定します。

2 ログプロセッサの作成

# Create a text handler to write the log to a file
file_handler = logging.FileHandler(filename='py34.log',encoding='utf-8')


file_handler.setLevel('WARNING') # Set the logging level of the handler


# Create a console handler to output logs to the console
console_handler = logging.StreamHandler()
console_handler.setLevel('INFO') # Set the console handler's logging level


ログハンドラは、指定された場所にログを送信するものです。

FileHandler ログをファイルに送信する

StreaHandler sys.stdout、sys.stderr、または任意のファイルのようなオブジェクトなどのデータストリームにロギング出力を送信するためにそれを送信します。sys.stdoutはデフォルトのコンソールです。

RotatingFileHandler ログファイルのサイズに応じたローテーションをサポート

TimedRotatingFileHandler 時間を基準にしたログファイルのローテーションに対応

詳しくは公式ドキュメントをご覧ください

( https://docs.python.org/zh-cn/3/library/logging.handlers.html?utm_source=testingpai.com#module-logging.handlers )

3 フォーマッタを作成する

formatter = logging.Formatter(fmt='%(levelname)s %(asctime)s [%(filename)s-->line:%(lineno)d]:%(message)s')


フォーマッタをプロセッサに設定する必要があります。

file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)


4 フィルタを作成する

フィルタは、指定されたログをフィルタリングするために使用されます。具体的な使用方法は省略され、通常は使用されません。

詳しくは公式ドキュメントをご覧ください

( https://docs.python.org/zh-cn/3/howto/logging-cookbook.html?utm_source=testingpai.com#filters-contextual )

5 プロセッサをロガーに追加する

logger.addHandler(file_handler)
logger.addHandler(console_handler)


6 ログを記録する

logger.info('This is a info')


2020-09-11 22:22:44,095-[->line:1]-INFO:This is a info.

logger.warning('This is a warning')


2020-09-11 22:23:20,337-[->line:1]-WARNING: これは警告です。

III. ロギングモジュールラッパー

機能的な分析

  • ロガー名のカスタマイズ機能
  • ログファイル名とパスのカスタマイズ機能
  • ログファイルのエンコード方式をカスタマイズする機能
  • ログフォーマットをカスタマイズする機能
  • タイムローテーションプロセッサを使用し、設定できること

関数にラップする

commonディレクトリにlog_handler.pyモジュールを作成し、その中に以下の関数を作成します。

import logging
from logging.handlers import TimedRotatingFileHandler
def get_logger(name, filename, encoding='utf-8', fmt=None, when='d', interval=1, backup_count=7, debug=False):
    """
    :param name: the name of the logger
    :param filename: the name of the log file (including the path)
    :param encoding: character encoding
    :param fmt: the format of the log
    :param when: log rotation time unit
    :param interval: interval
    :param backup_count: number of log files
    :param debug: debugging mode
    :return:
    """
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)
    # The level of the file processor must be higher than the console in general
    if debug:
        file_level = logging.DEBUG
        console_level = logging.DEBUG
    else:
        file_level = logging.WARNING
        console_level = logging.INFO
    if fmt is None:
        fmt = '%(levelname)s %(asctime)s [%(filename)s-->line:%(lineno)d]:%(message)s'
    file_handler = TimedRotatingFileHandler(
        filename=filename, when=when, interval=interval, backupCount=backup_count, encoding=encoding)
    file_handler.setLevel(file_level)
    console_handler = logging.StreamHandler()
    console_handler.setLevel(console_level)
    formatter = logging.Formatter(fmt=fmt)
    file_handler.setFormatter(formatter)
    console_handler.setFormatter(formatter)
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)
    return logger
if __name__ == '__main__':
    log = get_logger(name='py41', filename='py41.log', debug=True, when='s')
    log.info('I am a general message')
    import time
    time.sleep(3)
    log.warning('I am a warning message')


IV. プロジェクトに応募する

にインポートする

ロガー生成関数は、Excelデータ読み込み関数のように、ユースケースモジュールごとに1回インポートすることはできません。ロガーオブジェクトを返すため、同じロガー名でロガー生成関数を複数回呼び出すと、同じロガーに複数のログプロセッサが追加され、ロガーが重複してしまうからです。

上記の問題を解決するために、共通フォルダに イニット このファイルは common モジュールがインポートされたときに、一度だけ自動的にこのファイルにあるコードを実行します。

での イニット .py ファイルに以下のコードを記述してください。

from .log_handler import get_logger
logger = get_logger('py41', 'py38.log')


そして、プロジェクト内の他のモジュールでは、次のコードでインポートすることができます。

from common import logger


これにより、get_logger メソッドはプロジェクト実行中に一度だけ実行されるようになります。

ログの記録

ログの目的は、プログラムの実行状態を記録し、エラーが発生したときにその場所を特定し、分析するための基礎を提供することです。

いつ、何を記録するかは、各人のプログラムに対する理解や経験に基づいて決定されます。

私たちのプロジェクトでは、プロセスがユースケースの実行の中心にあるため、ロギングもユースケースの実行が中心になっています。

ロギングを使用して、各ユースケースのテストデータ、およびテスト結果を、次のようなコードで記録します。

...
@list_data(*cases)
    def test_login(self, case):
        """
        Login test
        """
        logger.info('Test case [{}] started testing'.format(case['title']))
        # 1. test data
        # The case parameters passed in
        logger.info('Test data for test case [{}] is:{}'.format(case['title'], case))
        # 2. test steps
        res = login_check(case['username'], case['password'])
        logger.info('The result of test case [{}] is:{}'.format(case['title'], res))
        # 3. assertion
        try:
            self.assertEqual(res, case['expect'])
        except AssertionError as e:
            logger.error('Test case [{}] assertion failed'.format(case['title']))
            raise e
        else:
            logger.info('Test case [{}] asserted successfully'.format(case['title']))
        finally:
            logger.info('Test case [{}] test ended')


上記は、3分でログを介してバグを見つけるためにPythonの自動化テストの詳細であり、バグを見つけるためにログについての詳細は、スクリプトハウスの他の関連記事に注意を払うしてください