Alvaro Aguilar
Alvaro Aguilar

Reputation: 736

How to prevent logging to file and capture logs for assertions using Pytest

I have a suite of unit tests for a python module and use Pytest to run those tests. I am now starting to use the standard logging library in my library and would need help solving two issues:

  1. How to prevent logs into files when running the test suite, to prevent files growing and to prevent unhelpful entries in real log files.
  2. How to capture the logs inside unit tests, to be able to run assertions on the logs that the library generates.

The module that I am trying to test configures the logging library in __init__.py to log into a file and logs entries in the module code using the info method. That works fine and when I run the code the right log entries appear in the file ok. -- see code below --

I have tried to use the caplog fixture in pytest -- see code and output below -- but the effect I get is:


Unit Tests Code

import library.module

class TestFunction:

    def test_something_else(self):
        library.module.function():
        assert True

    def test_logs(self,caplog)
        library.module.function():
        assert "desired" in caplog.text

Test Output

(...)
>     assert "desired" in caplog.text
E     AssertionError: assert 'desired' in ''
E      + where '' = <_pytest.logging.LogCaptureFixture object at (...).text
(...)

Log entries after running test suite

2021-12-07 11:10:05,915 - library.module - INFO - desired
2021-12-07 11:10:05,917 - library.module - INFO - desired

Logging module configuration

__init__.py

import logging.config
import yaml

with open("logging.yaml") as f:
    conf_dict = yaml.safe_load(f)
    logging.config.dictConfig(conf_dict)

logging.yaml

version: 1
formatters:
    simple:
        format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:    
    training:
        class: logging.FileHandler
        level: DEBUG
        formatter: simple
        filename: logs/test_log
loggers:
    library.module:
        level: DEBUG
        handlers: [training]
        propagate: no
root:
    level: DEBUG
    handlers: []

Module under test

import logging
logger = logging.getLogger(__name__)

def function():
    logger.info("desired")

File Structure

.
├── library
│   ├── module.py
│   └── __init__.py
├── tests
│   └── test_module.py
└── logs
    └── test_log

Upvotes: 1

Views: 828

Answers (1)

Laurent
Laurent

Reputation: 13458

To avoid writing to the log file, I suggest that, in test_module.py, you simply mock the logger and use it in your test, like this:

import pytest
import library.module

@pytest.fixture
def logger(mocker):
    return mocker.patch("library.module.logger.info")


class TestFunction:

    def test_something_else(self):
        library.module.function():
        assert True

    def test_logs(self,logger)
        library.module.function():
        logger.assert_called_with("desired")

Upvotes: 1

Related Questions