Quản lý và tùy chỉnh nhật ký trong Pytest

Mặc định, Pytest tự động thu thập các bản ghi mức WARNING trở lên. Khi một test thất bại, thông tin log sẽ được hiển thị cùng với stdoutstderr trong phần tóm tắt kết quả.

Khi chạy lệnh:

pytest

Kết quả lỗi sẽ có dạng:

----------------------- Captured stdlog call ----------------------
test_example.py    26 WARNING  nội dung log
----------------------- Captured stdout call ----------------------
nội dung stdout
----------------------- Captured stderr call ----------------------
nội dung stderr
==================== 2 failed in 0.02 seconds =====================

Bạn có thể tùy chỉnh định dạng hiển thị log bằng cách dùng các tùy chọn dòng lệnh:

pytest --log-format="%(asctime)s [%(levelname)s] %(message)s" \
       --log-date-format="%d/%m/%Y %H:%M:%S"

Hoặc cấu hình trong file pytest.ini:

[pytest]
log_format = %(asctime)s [%(levelname)s] %(message)s
log_date_format = %d/%m/%Y %H:%M:%S

Để tắt hoàn toàn việc ghi lại log/stdout/stderr khi test thất bại:

pytest --show-capture=no

Sử dụng fixture caplog để kiểm soát log trong test

Fixture caplog cho phép bạn điều chỉnh mức độ log trong quá trình test:

def test_demo_log_level(caplog):
    caplog.set_level("INFO")
    # mã test ở đây

Có thể chỉ định logger cụ thể:

def test_specific_logger(caplog):
    caplog.set_level("CRITICAL", logger="app.module_x")

Dùng context manager để thay đổi tạm thời:

def test_temporary_level(caplog):
    with caplog.at_level("DEBUG", logger="app.utils"):
        # đoạn code cần debug
        pass

Truy cập các bản ghi đã thu thập:

def test_validate_logs(caplog):
    some_function()
    assert not any(r.levelname == "ERROR" for r in caplog.records)
    assert "lỗi nghiêm trọng" not in caplog.text

Kiểm tra nhanh bằng tuple:

def test_log_content(caplog):
    logging.info("Xin chào %s", "Pytest")
    assert caplog.record_tuples == [("root", 20, "Xin chào Pytest")]

Xóa log đã ghi trong test:

def test_with_clearing(caplog):
    noisy_function()
    caplog.clear()
    clean_test_logic()
    assert [r.message for r in caplog.records] == ["Thành công"]

Truy cập log từ các giai đoạn khác (setup/call/teardown):

@pytest.fixture
def safe_env(caplog):
    env = setup_environment()
    yield env
    for phase in ("setup", "call"):
        warnings = [
            rec.message 
            for rec in caplog.get_records(phase) 
            if rec.levelno >= logging.WARNING
        ]
        if warnings:
            pytest.fail(f"Cảnh báo phát sinh: {warnings}")

Kích hoạt log trực tiếp ra console

Thêm vào pytest.ini:

[pytest]
log_cli = true
log_cli_level = INFO
log_cli_format = %(asctime)s | %(name)s | %(levelname)s | %(message)s

Hoặc dùng tùy chọn dòng lệnh:

pytest --log-cli-level=DEBUG --log-cli-format="%(message)s"

Ghi log ra file

Cấu hình trong pytest.ini:

[pytest]
log_file = logs/test_run.log
log_file_level = DEBUG
log_file_format = %(asctime)s - %(levelname)s - %(message)s

Hoặc đặt tên file log động trong conftest.py:

import os
from datetime import datetime

def pytest_configure(config):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    log_dir = os.path.join(config.rootdir, "logs")
    os.makedirs(log_dir, exist_ok=True)
    config.option.log_file = os.path.join(log_dir, f"test_{timestamp}.log")

Lưu ý về tương thích phiên bản

Tính năng log tích hợp thay thế plugin pytest-catchlog cũ. Để tắt tính năng log mới và quay lại dùng plugin cũ:

[pytest]
addopts = -p no:logging

Từ Pytest 3.4, hành vi mặc định thay đổi:

  • Mức log không còn bị ép buộc trừ khi bạn chỉ định rõ ràng.
  • Log trực tiếp ra console bị tắt mặc định — cần bật log_cli=true.
  • Log CLI giờ xuất ra sys.stdout, không cần dùng -s.

Để khôi phục hành vi cũ (giống Pytest 3.3):

[pytest]
log_cli = true
log_level = NOTSET

Thẻ: pytest python-testing logging caplog pytest-configuration

Đăng vào ngày 8 tháng 6 lúc 23:30