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

Time:12-12

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:

  • log entries are included into the file (logs generated in the runs from the test using caplog and all other tests)
  • caplog.text is empty

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

CodePudding user response:

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")
  • Related