summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Collins <robertc@robertcollins.net>2011-11-22 21:12:48 +1300
committerRobert Collins <robertc@robertcollins.net>2011-11-22 21:12:48 +1300
commitd74b83414b8a473651bb392e72c1ae80ffcf747b (patch)
treeeb94cca9d017ada3f6adebd47d5e5bb90776b2e0
parente9a67fab46df2cbb598e8bebadf03091731099b7 (diff)
parente6718e6dfcdc14bb7c668a945aaa087a66442ade (diff)
downloadfixtures-d74b83414b8a473651bb392e72c1ae80ffcf747b.tar.gz
Add new LoggingFixture fixture for replacing logging Loggers.
-rw-r--r--NEWS3
-rw-r--r--lib/fixtures/__init__.py2
-rw-r--r--lib/fixtures/_fixtures/__init__.py2
-rw-r--r--lib/fixtures/_fixtures/logger.py73
-rw-r--r--lib/fixtures/tests/_fixtures/__init__.py1
-rw-r--r--lib/fixtures/tests/_fixtures/test_logger.py78
6 files changed, 159 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 0350290..6b6a76c 100644
--- a/NEWS
+++ b/NEWS
@@ -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)