I am having a problem when using pytest and logging together. When I run a program on its own, I can see its messages printed on screen as well as in the file test.log.
python3 main.py -> prints on terminal, and also in test.log
However, when I am running the same program with pytest, I am seeing the messages only on screen, but the file test.log is not being created.
pytest -vs test -> prints only on terminal, but not in test.log
Why is pytest interfering with the logging utility, and what should I do to create these log files when using pytest?
My versions are the following:
platform linux -- Python 3.6.7, pytest-4.0.2, py-1.7.0, pluggy-0.8.0 -- /usr/bin/python3
The directory structure is the following:
├── logger.py
├── main.py
└── test
├── __init__.py
└── test_module01.py
The code for these files are given below:
# logger.py ===================================
import logging
def logconfig(logfile, loglevel):
print('logconfig: logfile={} loglevel={}..'.format(logfile,loglevel))
logging.basicConfig(filename=logfile, level=logging.INFO, format='%(asctime)s :: %(message)s')
def logmsg(log_level, msg):
print(log_level,': ',msg)
logging.info('INFO: ' + msg)
# main.py =====================================
from datetime import datetime
from logger import *
def main(BASE_DIR):
LOG_FILE = BASE_DIR + 'test.log'
logconfig(LOG_FILE,'INFO')
logmsg('INFO',"Starting PROGRAM@[{}] at {}=".format(BASE_DIR,datetime.now()))
logmsg('INFO',"Ending PROGRAM at {}=".format(datetime.now()))
if __name__ == "__main__":
main('./')
# __init__.py =================================
all = ["test_module01"]
# test_module01.py ============================
import pytest
import main
class TestClass01:
def test_case01(self):
print("In test_case01()")
main.main('./test/')
Pytest does not support this by default, but you can add a custom option to your conftest.py to turn off specific loggers.
By setting the log_cli configuration option to true , pytest will output logging records as they are emitted directly into the console. You can specify the logging level for which log records with equal or higher level are printed to the console by passing --log-cli-level .
By default, pytest captures all log records emitted by your program. This means that all logging handlers defined in your code will be replaced with the custom handler pytest
uses internally; if you pass -s
, it will print the emitted records to the terminal, otherwise it will print nothing and no further output is being made. The internal handler will capture all records emitted from your code. To access them in the tests, use the caplog
fixture. Example: imagine you need to test the following program:
import logging
import time
def spam():
logging.basicConfig(level=logging.CRITICAL)
logging.debug('spam starts')
time.sleep(1)
logging.critical('Oopsie')
logging.debug('spam ends')
if __name__ == '__main__':
spam()
If you run the program, you'll see the output
CRITICAL:root:Oopsie
but there's no obvious way to access the debug messages. No problem when using caplog
:
def test_spam(caplog):
with caplog.at_level(logging.DEBUG):
spam()
assert len(caplog.records) == 3
assert caplog.records[0].message == 'spam starts'
assert caplog.records[-1].message == 'spam ends'
If you don't need log capturing (for example, when writing system tests with pytest
), you can turn it off by disabling the logging
plugin:
$ pytest -p no:logging
Or persist it in the pytest.cfg
to not having to enter it each time:
[pytest]
addopts = -p no:logging
Of course, once the log capturing is explicitly disabled, you can't rely on caplog
anymore.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With