diff options
author | Robert Collins <robertc@robertcollins.net> | 2011-11-22 21:12:48 +1300 |
---|---|---|
committer | Robert Collins <robertc@robertcollins.net> | 2011-11-22 21:12:48 +1300 |
commit | d74b83414b8a473651bb392e72c1ae80ffcf747b (patch) | |
tree | eb94cca9d017ada3f6adebd47d5e5bb90776b2e0 | |
parent | e9a67fab46df2cbb598e8bebadf03091731099b7 (diff) | |
parent | e6718e6dfcdc14bb7c668a945aaa087a66442ade (diff) | |
download | fixtures-d74b83414b8a473651bb392e72c1ae80ffcf747b.tar.gz |
Add new LoggingFixture fixture for replacing logging Loggers.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | lib/fixtures/__init__.py | 2 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/__init__.py | 2 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/logger.py | 73 | ||||
-rw-r--r-- | lib/fixtures/tests/_fixtures/__init__.py | 1 | ||||
-rw-r--r-- | lib/fixtures/tests/_fixtures/test_logger.py | 78 |
6 files changed, 159 insertions, 0 deletions
@@ -8,6 +8,9 @@ IN DEVELOPMENT CHANGES: +* New fixture LoggerFixture which replaces a logging module logger. + (Free Ekanayaka) + * On Python 2.7 and above the _fixtures tests are no longer run twice. (Robert Collins) diff --git a/lib/fixtures/__init__.py b/lib/fixtures/__init__.py index 20260d4..fbdd845 100644 --- a/lib/fixtures/__init__.py +++ b/lib/fixtures/__init__.py @@ -42,6 +42,7 @@ __all__ = [ 'EnvironmentVariableFixture', 'Fixture', 'FunctionFixture', + 'LoggerFixture', 'MethodFixture', 'MonkeyPatch', 'PackagePathEntry', @@ -56,6 +57,7 @@ __all__ = [ from fixtures.fixture import Fixture, FunctionFixture, MethodFixture from fixtures._fixtures import ( EnvironmentVariableFixture, + LoggerFixture, MonkeyPatch, PackagePathEntry, PopenFixture, diff --git a/lib/fixtures/_fixtures/__init__.py b/lib/fixtures/_fixtures/__init__.py index 6287242..082c936 100644 --- a/lib/fixtures/_fixtures/__init__.py +++ b/lib/fixtures/_fixtures/__init__.py @@ -18,6 +18,7 @@ __all__ = [ 'EnvironmentVariableFixture', + 'LoggerFixture', 'MonkeyPatch', 'PackagePathEntry', 'PopenFixture', @@ -28,6 +29,7 @@ __all__ = [ from fixtures._fixtures.environ import EnvironmentVariableFixture +from fixtures._fixtures.logger import LoggerFixture from fixtures._fixtures.monkeypatch import MonkeyPatch from fixtures._fixtures.popen import PopenFixture from fixtures._fixtures.packagepath import PackagePathEntry diff --git a/lib/fixtures/_fixtures/logger.py b/lib/fixtures/_fixtures/logger.py new file mode 100644 index 0000000..13d0fa6 --- /dev/null +++ b/lib/fixtures/_fixtures/logger.py @@ -0,0 +1,73 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2011, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +from logging import StreamHandler, getLogger, INFO, Formatter +from cStringIO import StringIO + +from fixtures import Fixture + +__all__ = [ + 'LoggerFixture', + ] + + +class LoggerFixture(Fixture): + """Replace a logger and capture it's output.""" + + def __init__(self, name="", level=INFO, format=None, nuke_handlers=True): + """Create a LoggerFixture. + + :param name: The name of the logger to replace. Defaults to "". + :param level: The log level to set, defaults to INFO. + :param format: Logging format to use. Defaults to capturing supplied + messages verbatim. + :param nuke_handlers: If True remove all existing handles (prevents + existing messages going to e.g. stdout). Defaults to True. + + Example: + + def test_log(self) + fixture = self.useFixture(LoggerFixture()) + logging.info('message') + self.assertEqual('message', fixture.output) + """ + super(LoggerFixture, self).__init__() + self._name = name + self._level = level + self._format = format + self._nuke_handlers = nuke_handlers + + def setUp(self): + super(LoggerFixture, self).setUp() + self._output = StringIO() + logger = getLogger(self._name) + if self._level: + self.addCleanup(logger.setLevel, logger.level) + logger.setLevel(self._level) + if self._nuke_handlers: + for handler in reversed(logger.handlers): + logger.removeHandler(handler) + self.addCleanup(logger.addHandler, handler) + handler = StreamHandler(self._output) + if self._format: + handler.setFormatter(Formatter(self._format)) + try: + logger.addHandler(handler) + finally: + self.addCleanup(logger.removeHandler, handler) + + @property + def output(self): + return self._output.getvalue() diff --git a/lib/fixtures/tests/_fixtures/__init__.py b/lib/fixtures/tests/_fixtures/__init__.py index e41bcc7..b4d4be0 100644 --- a/lib/fixtures/tests/_fixtures/__init__.py +++ b/lib/fixtures/tests/_fixtures/__init__.py @@ -16,6 +16,7 @@ def load_tests(loader, standard_tests, pattern): test_modules = [ 'environ', + 'logger', 'monkeypatch', 'packagepath', 'popen', diff --git a/lib/fixtures/tests/_fixtures/test_logger.py b/lib/fixtures/tests/_fixtures/test_logger.py new file mode 100644 index 0000000..89b8994 --- /dev/null +++ b/lib/fixtures/tests/_fixtures/test_logger.py @@ -0,0 +1,78 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2011, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +import logging + +from testtools import TestCase +from cStringIO import StringIO + +from fixtures import LoggerFixture, TestWithFixtures + + +class LoggerFixtureTest(TestCase, TestWithFixtures): + + def setUp(self): + super(LoggerFixtureTest, self).setUp() + self.logger = logging.getLogger() + self.addCleanup(self.removeHandlers, self.logger) + + def removeHandlers(self, logger): + for handler in logger.handlers: + logger.removeHandler(handler) + + def test_output_property_has_output(self): + fixture = self.useFixture(LoggerFixture()) + logging.info("some message") + self.assertEqual("some message\n", fixture.output) + + def test_replace_and_restore_handlers(self): + stream = StringIO() + logger = logging.getLogger() + logger.addHandler(logging.StreamHandler(stream)) + logger.setLevel(logging.INFO) + logging.info("one") + fixture = LoggerFixture() + with fixture: + logging.info("two") + logging.info("three") + self.assertEqual("two\n", fixture.output) + self.assertEqual("one\nthree\n", stream.getvalue()) + + def test_preserving_existing_handlers(self): + stream = StringIO() + self.logger.addHandler(logging.StreamHandler(stream)) + self.logger.setLevel(logging.INFO) + fixture = LoggerFixture(nuke_handlers=False) + with fixture: + logging.info("message") + self.assertEqual("message\n", fixture.output) + self.assertEqual("message\n", stream.getvalue()) + + def test_logging_level_restored(self): + self.logger.setLevel(logging.DEBUG) + fixture = LoggerFixture(level=logging.WARNING) + with fixture: + # The fixture won't capture this, because the DEBUG level + # is lower than the WARNING one + logging.debug("debug message") + self.assertEqual(logging.WARNING, self.logger.level) + self.assertEqual("", fixture.output) + self.assertEqual(logging.DEBUG, self.logger.level) + + def test_custom_format(self): + fixture = LoggerFixture(format="%(module)s") + self.useFixture(fixture) + logging.info("message") + self.assertEqual("test_logger\n", fixture.output) |