pytest
testing
logging
Python
test automation

Logging within pytest tests

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Logging inside pytest tests is useful for debugging failures, but it is most effective when it is intentional rather than noisy. Pytest already captures log output, so the real question is how to configure it, view it when needed, and assert on it in tests.

Basic Logging in a Test

You can use Python's standard logging module directly inside a test or inside the code under test:

python
1import logging
2
3logger = logging.getLogger(__name__)
4
5
6def test_example():
7    logger.info("starting test_example")
8    assert 2 + 2 == 4

By default, pytest captures log records and only shows them when the test fails or when logging output is explicitly enabled on the command line.

Showing Logs During Test Runs

If you want logs to appear live in the terminal, use pytest's logging options:

bash
pytest --log-cli-level=INFO

You can make that behavior persistent in pytest.ini:

ini
1[pytest]
2log_cli = true
3log_cli_level = INFO
4log_format = %(asctime)s %(levelname)s %(name)s %(message)s

This is useful when diagnosing flaky tests or long-running integration tests where you want visibility before a failure occurs.

Asserting on Logs With caplog

The caplog fixture is the best way to test logging behavior. It captures emitted log records so you can assert that expected messages were produced.

python
1import logging
2
3
4def process_order(order_id):
5    logging.getLogger("orders").warning("order %s is delayed", order_id)
6
7
8def test_process_order_logs_warning(caplog):
9    with caplog.at_level(logging.WARNING, logger="orders"):
10        process_order(42)
11
12    assert "order 42 is delayed" in caplog.text

This is much stronger than printing text to the console because it verifies the application emitted the correct log event at the correct severity.

You can also inspect structured log records:

python
1def test_log_level(caplog):
2    logger = logging.getLogger("payments")
3
4    with caplog.at_level(logging.INFO, logger="payments"):
5        logger.info("payment accepted")
6
7    assert caplog.records[0].levelname == "INFO"
8    assert caplog.records[0].name == "payments"

Configure Logging Once

For larger projects, centralize logging setup rather than repeating basicConfig in every test. If the application already configures logging, tests should usually reuse that configuration or override it in a fixture.

python
1import logging
2import pytest
3
4
5@pytest.fixture(autouse=True)
6def configure_logging():
7    logging.getLogger("myapp").setLevel(logging.DEBUG)

This keeps test files focused on behavior rather than setup noise.

When Logging Helps, and When It Hurts

Logs are excellent for integration tests, async workflows, retries, and state transitions that are hard to see from assertions alone. They are less helpful when every test emits many low-value messages. A test suite that floods the terminal with INFO logs often hides the lines that matter.

Use logs to explain meaningful transitions, warnings, and failures. Use assertions to prove correctness. The two tools work well together when they are not forced into the same role.

When a failure is intermittent, temporarily raising the log level for one test module is often more effective than enabling verbose logging for the entire suite. That keeps the signal focused on the code path you are actively debugging.

Common Pitfalls

  • Calling logging.basicConfig in many test modules can create inconsistent formatting and duplicate handlers.
  • Writing assertions against printed output instead of log records misses the structure and severity of the event.
  • Setting the global log level too low can overwhelm the test output and hide important failures.
  • Forgetting to scope caplog.at_level to a specific logger may capture unrelated noise from dependencies.
  • Treating logs as a substitute for assertions makes tests harder to maintain and less precise.

Summary

  • Pytest already captures logs, so you can enable them when needed instead of printing everything by default.
  • Use --log-cli-level or pytest.ini to control live log visibility.
  • Use caplog to assert on logging behavior in tests.
  • Keep logging configuration centralized and predictable.
  • Prefer focused, meaningful logs that support assertions instead of replacing them.

Course illustration
Course illustration

All Rights Reserved.