Home > Net >  unittest & logging | capture logs sent to StreamHandler(sys.stdout)
unittest & logging | capture logs sent to StreamHandler(sys.stdout)

Time:09-30

I want to capture logs that are sent to Stream.

MyCode.py passes log to console: 2021-09-29 15:06:11,382 - root - ERROR - Started. However, captured.records returns nothing. (First 2 lines in output)

Sources


Questions

  • Why does captured return nothing?
  • How can I capture logs sent to StreamHandler(sys.stdout)?

MyCode.py:

import logging
import sys

logger = logging.getLogger()
streamHandler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
streamHandler.setFormatter(formatter)
logger.addHandler(streamHandler)
logger.error('Started')

main.py:

import unittest
from unittest import TestCase
import MyCode

class TestExample(TestCase):
    def test_logging(self):
        with self.assertLogs() as captured:
            print('captured.records: ', captured.records)
            self.assertEqual(len(captured.records), 1)
            self.assertTrue("Started" in captured.records[0].getMessage())

if __name__ == '__main__':
    unittest.main()

Console:

2021-09-29 15:06:11,382 - root - ERROR - Started
captured.records:  []
F
======================================================================
FAIL: test_logging (__main__.TestExample)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "main.py", line 9, in test_logging
    self.assertEqual(len(captured.records), 1)
AssertionError: 0 != 1

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)
repl process died unexpectedly: exit status 1

Please let me know if there's anything else I should add to post.

CodePudding user response:

The assertLogs context manager only captures log messages that are created in its context. Your log messages were created when MyCode was imported, which happened before the log assertion context was created.

If you put your code in a function, and run that function within the test, it should work.

MyCode.py:

import logging
import sys

def foo():
    logger = logging.getLogger()
    streamHandler = logging.StreamHandler(sys.stdout)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - (message)s')
    streamHandler.setFormatter(formatter)
    logger.addHandler(streamHandler)
    logger.error('Started')

main.py:

import unittest
from unittest import TestCase
import MyCode

class TestExample(TestCase):
    def test_logging(self):
        with self.assertLogs() as captured:
            MyCode.foo()
            print('captured.records: ', captured.records)
            self.assertEqual(len(captured.records), 1)
            self.assertTrue("Started" in captured.records[0].getMessage())

if __name__ == '__main__':
    unittest.main()
  • Related