diff options
author | Robert Collins <robertc@robertcollins.net> | 2012-12-11 14:16:43 +1300 |
---|---|---|
committer | Robert Collins <robertc@robertcollins.net> | 2012-12-11 14:16:43 +1300 |
commit | b16be6d13a702224432e9836ef2d5b23c765d34e (patch) | |
tree | f36cc5253a8cc74b9af76c07a617db0566b56fd5 | |
parent | cc2c7448d10c8f9fb83dc506ce04aaaab8e38269 (diff) | |
parent | af26cb9e360976ebebadabb39769009d51b2eb7e (diff) | |
download | fixtures-b16be6d13a702224432e9836ef2d5b23c765d34e.tar.gz |
* New ``DetailStream`` fixture to add file-like object content to testtools
details. This allows for easy capture of sys.stdout and sys.stderr for
example. (Clark Boylan)
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | README | 15 | ||||
-rw-r--r-- | lib/fixtures/__init__.py | 2 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/__init__.py | 2 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/detailstream.py | 43 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/logger.py | 11 | ||||
-rw-r--r-- | lib/fixtures/tests/_fixtures/__init__.py | 1 | ||||
-rw-r--r-- | lib/fixtures/tests/_fixtures/test_detailstream.py | 54 |
8 files changed, 125 insertions, 9 deletions
@@ -6,6 +6,9 @@ fixtures release notes NEXT ~~~~ +New ``DetailStream`` fixture to add file-like object content to testtools +details, cleanup logic factored out into a CallMany class. + CHANGES: * Add ``join`` method to ``TempDir`` to more readily get paths relative @@ -14,6 +17,9 @@ CHANGES: * Factor out new ``CallMany`` class to isolate the cleanup logic. (Robert Collins) +* New ``DetailStream`` fixture to add file-like object content to testtools + details. This allows for easy capture of sys.stdout and sys.stderr for + example. (Clark Boylan) 0.3.9 ~~~~~ @@ -28,7 +28,7 @@ Dependencies * Python 2.4+ This is the base language fixtures is written in and for. -* testtools <https://launchpad.net/testtools> 0.9.12 or newer. +* testtools <https://launchpad.net/testtools> 0.9.22 or newer. testtools provides helpful glue functions for the details API used to report information about a fixture (whether its used in a testing or production environment). @@ -266,6 +266,19 @@ In addition to the Fixture, FunctionFixture and MethodFixture classes fixtures includes a number of precanned fixtures. The API docs for fixtures will list the complete set of these, should the dcs be out of date or not to hand. +DetailStream +++++++++++++ + +Trivial adapter to make a StringIO (though it may in future auto-spill to disk +for large content) and expose that as a detail object, for automatic inclusion +in test failure descriptions. Very useful in combination with MonkeyPatch. + + >>> fixture = fixtures.DetailStream('stdout') + >>> fixture.setUp() + >>> with fixtures.MonkeyPatch('sys.stdout', fixture.stream): + ... pass + >>> fixture.cleanUp() + EnvironmentVariable +++++++++++++++++++ diff --git a/lib/fixtures/__init__.py b/lib/fixtures/__init__.py index c0b0d48..9b9d3b6 100644 --- a/lib/fixtures/__init__.py +++ b/lib/fixtures/__init__.py @@ -39,6 +39,7 @@ Most users will want to look at TestWithFixtures and Fixture, to start with. __version__ = (0, 3, 9, 'final', 0) __all__ = [ + 'DetailStream', 'EnvironmentVariable', 'EnvironmentVariableFixture', 'FakeLogger', @@ -67,6 +68,7 @@ from fixtures.fixture import ( MethodFixture, ) from fixtures._fixtures import ( + DetailStream, EnvironmentVariable, EnvironmentVariableFixture, FakeLogger, diff --git a/lib/fixtures/_fixtures/__init__.py b/lib/fixtures/_fixtures/__init__.py index ec88780..d6a8700 100644 --- a/lib/fixtures/_fixtures/__init__.py +++ b/lib/fixtures/_fixtures/__init__.py @@ -17,6 +17,7 @@ """Included fixtures.""" __all__ = [ + 'DetailStream', 'EnvironmentVariable', 'EnvironmentVariableFixture', 'FakeLogger', @@ -35,6 +36,7 @@ __all__ = [ ] +from fixtures._fixtures.detailstream import DetailStream from fixtures._fixtures.environ import ( EnvironmentVariable, EnvironmentVariableFixture, diff --git a/lib/fixtures/_fixtures/detailstream.py b/lib/fixtures/_fixtures/detailstream.py new file mode 100644 index 0000000..779ef18 --- /dev/null +++ b/lib/fixtures/_fixtures/detailstream.py @@ -0,0 +1,43 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2012, 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. + +__all__ = [ + 'DetailStream' + ] + +from cStringIO import StringIO + +from fixtures import Fixture +import testtools + + +class DetailStream(Fixture): + """Provide a file-like object and expose it as a detail. + + :attr stream: The file-like object. + """ + + def __init__(self, detail_name): + """Create a DetailStream. + + :param detail_name: Use this as the name of the stream. + """ + self._detail_name = detail_name + + def setUp(self): + super(DetailStream, self).setUp() + self.stream = StringIO() + self.addDetail(self._detail_name, + testtools.content.content_from_stream(self.stream, seek_offset=0)) diff --git a/lib/fixtures/_fixtures/logger.py b/lib/fixtures/_fixtures/logger.py index 4b85b22..ec5a767 100644 --- a/lib/fixtures/_fixtures/logger.py +++ b/lib/fixtures/_fixtures/logger.py @@ -14,12 +14,9 @@ # limitations under that license. from logging import StreamHandler, getLogger, INFO, Formatter -from cStringIO import StringIO - -from testtools.content import Content -from testtools.content_type import UTF8_TEXT from fixtures import Fixture +from fixtures._fixtures.detailstream import DetailStream __all__ = [ 'FakeLogger', @@ -55,10 +52,8 @@ class FakeLogger(Fixture): def setUp(self): super(FakeLogger, self).setUp() - output = StringIO() - self.addDetail( - u"pythonlogging:'%s'" % self._name, - Content(UTF8_TEXT, lambda: [output.getvalue()])) + name = u"pythonlogging:'%s'" % self._name + output = self.useFixture(DetailStream(name)).stream self._output = output logger = getLogger(self._name) if self._level: diff --git a/lib/fixtures/tests/_fixtures/__init__.py b/lib/fixtures/tests/_fixtures/__init__.py index d8e0979..38987b9 100644 --- a/lib/fixtures/tests/_fixtures/__init__.py +++ b/lib/fixtures/tests/_fixtures/__init__.py @@ -15,6 +15,7 @@ def load_tests(loader, standard_tests, pattern): test_modules = [ + 'detailstream', 'environ', 'logger', 'monkeypatch', diff --git a/lib/fixtures/tests/_fixtures/test_detailstream.py b/lib/fixtures/tests/_fixtures/test_detailstream.py new file mode 100644 index 0000000..9df351d --- /dev/null +++ b/lib/fixtures/tests/_fixtures/test_detailstream.py @@ -0,0 +1,54 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2012, 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 testtools import TestCase + +from fixtures import DetailStream + + +class DetailStreamTest(TestCase): + + def test_empty_detail_stream(self): + detail_name = 'test' + fixture = DetailStream(detail_name) + with fixture: + content = fixture.getDetails()[detail_name] + self.assertEqual("", content.as_text()) + + def test_stream_content_in_details(self): + detail_name = 'test' + fixture = DetailStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + # Output after getDetails is called is included. + stream.write("testing 1 2 3") + self.assertEqual("testing 1 2 3", content.as_text()) + + def test_stream_content_reset(self): + detail_name = 'test' + fixture = DetailStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + stream.write("testing 1 2 3") + with fixture: + # The old content object returns the old usage + self.assertEqual("testing 1 2 3", content.as_text()) + content = fixture.getDetails()[detail_name] + # A new fixture returns the new output: + stream = fixture.stream + stream.write("1 2 3 testing") + self.assertEqual("1 2 3 testing", content.as_text()) |