← Back to team overview

testtools-dev team mailing list archive

[Merge] lp:~lifeless/testtools/fixtures into lp:testtools

 

Robert Collins has proposed merging lp:~lifeless/testtools/fixtures into lp:testtools.

Requested reviews:
  testtools developers (testtools-dev)


useFixture. Woo.
-- 
https://code.launchpad.net/~lifeless/testtools/fixtures/+merge/39388
Your team testtools developers is requested to review the proposed merge of lp:~lifeless/testtools/fixtures into lp:testtools.
=== modified file 'MANUAL'
--- MANUAL	2010-10-17 16:34:55 +0000
+++ MANUAL	2010-10-26 16:56:50 +0000
@@ -116,6 +116,16 @@
 ``skipTest`` support, the ``skip`` name is now deprecated (but no warning
 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
 ~~~~~~~~~~~~~~~~~~~~~

=== modified file 'NEWS'
--- NEWS	2010-10-25 22:10:37 +0000
+++ NEWS	2010-10-26 16:56:50 +0000
@@ -24,6 +24,9 @@
 * addUnexpectedSuccess is translated to addFailure for test results that don't
   know about addUnexpectedSuccess.  (Jonathan Lange, #654474)
 
+* ``testools.TestCase.useFixture`` has been added to glue with fixtures nicely.
+  (Robert Collins)
+
 
 0.9.7
 ~~~~~

=== modified file 'README'
--- README	2010-10-24 08:46:03 +0000
+++ README	2010-10-26 16:56:50 +0000
@@ -19,14 +19,21 @@
 distributed under the same license as Python, see LICENSE for details.
 
 
-Dependencies
-------------
+Required Dependencies
+---------------------
 
  * Python 2.4+ or 3.0+
 
+Optional Dependencies
+---------------------
+
 If you would like to use our undocumented, unsupported Twisted support, then
 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
 -----------------------

=== modified file 'testtools/testcase.py'
--- testtools/testcase.py	2010-10-18 12:46:20 +0000
+++ testtools/testcase.py	2010-10-26 16:56:50 +0000
@@ -538,6 +538,35 @@
         """
         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):
         unittest.TestCase.setUp(self)
         self.__setup_called = True

=== modified file 'testtools/tests/test_testtools.py'
--- testtools/tests/test_testtools.py	2010-09-26 20:45:28 +0000
+++ testtools/tests/test_testtools.py	2010-10-26 16:56:50 +0000
@@ -6,6 +6,9 @@
 import sys
 import unittest
 
+import fixtures
+from fixtures.tests.helpers import LoggingFixture
+
 from testtools import (
     ErrorHolder,
     MultipleExceptions,
@@ -13,6 +16,7 @@
     TestCase,
     clone_test_with_new_id,
     content,
+    content_type,
     skip,
     skipIf,
     skipUnless,
@@ -1122,6 +1126,59 @@
         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():
     from unittest import TestLoader
     return TestLoader().loadTestsFromName(__name__)


Follow ups