* `testools.TestCase.useFixture` has been added to glue with fixtures nicely.

(Robert Collins)
This commit is contained in:
Robert Collins
2010-10-27 07:59:12 +13:00
5 changed files with 108 additions and 2 deletions

10
MANUAL
View File

@@ -116,6 +116,16 @@ instead. ``skipTest`` was previously known as ``skip`` but as Python 2.7 adds
``skipTest`` support, the ``skip`` name is now deprecated (but no warning ``skipTest`` support, the ``skip`` name is now deprecated (but no warning
is emitted yet - some time in the future we may do so). is emitted yet - some time in the future we may do so).
TestCase.useFixture
~~~~~~~~~~~~~~~~~~~
``useFixture(fixture)`` calls setUp on the fixture, schedules a cleanup to
clean it up, and schedules a cleanup to attach all details held by the
fixture to the details dict of the test case. The fixture object should meet
the ``fixtures.Fixture`` protocol (version 0.3.4 or newer). This is useful
for moving code out of setUp and tearDown methods and into composable side
classes.
New assertion methods New assertion methods
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~

3
NEWS
View File

@@ -24,6 +24,9 @@ Improvements
* addUnexpectedSuccess is translated to addFailure for test results that don't * addUnexpectedSuccess is translated to addFailure for test results that don't
know about addUnexpectedSuccess. (Jonathan Lange, #654474) know about addUnexpectedSuccess. (Jonathan Lange, #654474)
* ``testools.TestCase.useFixture`` has been added to glue with fixtures nicely.
(Robert Collins)
* Update documentation to say how to use testtools.run() on Python 2.4. * Update documentation to say how to use testtools.run() on Python 2.4.
(Jonathan Lange, #501174) (Jonathan Lange, #501174)

11
README
View File

@@ -19,14 +19,21 @@ is copyright Steve Purcell and the Python Software Foundation, it is
distributed under the same license as Python, see LICENSE for details. distributed under the same license as Python, see LICENSE for details.
Dependencies Required Dependencies
------------ ---------------------
* Python 2.4+ or 3.0+ * Python 2.4+ or 3.0+
Optional Dependencies
---------------------
If you would like to use our undocumented, unsupported Twisted support, then If you would like to use our undocumented, unsupported Twisted support, then
you will need Twisted. you will need Twisted.
If you want to use ``fixtures`` then you can either install fixtures (e.g. from
https://launchpad.net/python-fixtures or http://pypi.python.org/pypi/fixtures)
or alternatively just make sure your fixture objects obey the same protocol.
Bug reports and patches Bug reports and patches
----------------------- -----------------------

View File

@@ -538,6 +538,35 @@ class TestCase(unittest.TestCase):
""" """
return self._get_test_method()() return self._get_test_method()()
def useFixture(self, fixture):
"""Use fixture in a test case.
The fixture will be setUp, and self.addCleanup(fixture.cleanUp) called.
:param fixture: The fixture to use.
:return: The fixture, after setting it up and scheduling a cleanup for
it.
"""
fixture.setUp()
self.addCleanup(fixture.cleanUp)
self.addCleanup(self._gather_details, fixture.getDetails)
return fixture
def _gather_details(self, getDetails):
"""Merge the details from getDetails() into self.getDetails()."""
details = getDetails()
my_details = self.getDetails()
for name, content_object in details.items():
new_name = name
disambiguator = itertools.count(1)
while new_name in my_details:
new_name = '%s-%d' % (name, advance_iterator(disambiguator))
name = new_name
content_bytes = list(content_object.iter_bytes())
content_callback = lambda:content_bytes
self.addDetail(name,
content.Content(content_object.content_type, content_callback))
def setUp(self): def setUp(self):
unittest.TestCase.setUp(self) unittest.TestCase.setUp(self)
self.__setup_called = True self.__setup_called = True

View File

@@ -6,6 +6,9 @@ from pprint import pformat
import sys import sys
import unittest import unittest
import fixtures
from fixtures.tests.helpers import LoggingFixture
from testtools import ( from testtools import (
ErrorHolder, ErrorHolder,
MultipleExceptions, MultipleExceptions,
@@ -13,6 +16,7 @@ from testtools import (
TestCase, TestCase,
clone_test_with_new_id, clone_test_with_new_id,
content, content,
content_type,
skip, skip,
skipIf, skipIf,
skipUnless, skipUnless,
@@ -1122,6 +1126,59 @@ class TestPatchSupport(TestCase):
self.assertIs(marker, value) self.assertIs(marker, value)
class TestFixtureSupport(TestCase):
def test_useFixture(self):
fixture = LoggingFixture()
class SimpleTest(TestCase):
def test_foo(self):
self.useFixture(fixture)
result = unittest.TestResult()
SimpleTest('test_foo').run(result)
self.assertTrue(result.wasSuccessful())
self.assertEqual(['setUp', 'cleanUp'], fixture.calls)
def test_useFixture_cleanups_raise_caught(self):
calls = []
def raiser(ignored):
calls.append('called')
raise Exception('foo')
fixture = fixtures.FunctionFixture(lambda:None, raiser)
class SimpleTest(TestCase):
def test_foo(self):
self.useFixture(fixture)
result = unittest.TestResult()
SimpleTest('test_foo').run(result)
self.assertFalse(result.wasSuccessful())
self.assertEqual(['called'], calls)
def test_useFixture_details_captured(self):
class DetailsFixture(fixtures.Fixture):
def setUp(self):
fixtures.Fixture.setUp(self)
self.addCleanup(delattr, self, 'content')
self.content = ['content available until cleanUp']
self.addDetail('content',
content.Content(content_type.UTF8_TEXT, self.get_content))
def get_content(self):
return self.content
fixture = DetailsFixture()
class SimpleTest(TestCase):
def test_foo(self):
self.useFixture(fixture)
# Add a colliding detail (both should show up)
self.addDetail('content',
content.Content(content_type.UTF8_TEXT, lambda:['foo']))
result = ExtendedTestResult()
SimpleTest('test_foo').run(result)
self.assertEqual('addSuccess', result._events[-2][0])
details = result._events[-2][2]
self.assertEqual(['content', 'content-1'], sorted(details.keys()))
self.assertEqual('foo', ''.join(details['content'].iter_text()))
self.assertEqual('content available until cleanUp',
''.join(details['content-1'].iter_text()))
def test_suite(): def test_suite():
from unittest import TestLoader from unittest import TestLoader
return TestLoader().loadTestsFromName(__name__) return TestLoader().loadTestsFromName(__name__)