StressedBoi69420
StressedBoi69420

Reputation: 2066

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

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


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.

Upvotes: 0

Views: 585

Answers (1)

izzy18
izzy18

Reputation: 804

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()

Upvotes: 1

Related Questions