← Back to team overview

testtools-dev team mailing list archive

Re: [Merge] lp:~jml/testtools/extract-factory into lp:testtools

 

Does the factory need to be exposed at all?

On 15/12/2011 10:19 PM, "Jonathan Lange" <jml@xxxxxxxxx> wrote:

Jonathan Lange has proposed merging lp:~jml/testtools/extract-factory into
lp:testtools.

Requested ...
Your team testtools developers is subscribed to branch lp:testtools.

=== modified file 'NEWS'
--- NEWS        2011-12-05 15:33:37 +0000
+++ NEWS        2011-12-15 11:18:22 +0000
@@ -14,6 +14,14 @@
  ``MatchesAll`` with keyword arguments, then this change might affect your
  test results.  (Jonathan Lange)

+* ``TestCase`` now has a ``factory`` attribute, set to an instance of
+  ``ObjectFactory``.  It now uses this instance for generating unique
strings
+  and integers.  (Jonathan Lange)
+
+* ``TestCase.getUniqueInteger`` and ``TestCase.getUniqueString`` are now
+  deprecated.  Use ``TestCase.factory.getUniqueInteger`` and
+  ``TestCase.factory.getUniqueString`` instead.  (Jonathan Lange)
+
 Improvements
 ------------


=== modified file 'doc/for-test-authors.rst'
--- doc/for-test-authors.rst    2011-12-07 11:32:45 +0000
+++ doc/for-test-authors.rst    2011-12-15 11:18:22 +0000
@@ -1240,17 +1240,19 @@
 fine.  However, sometimes it's useful to be able to create arbitrary
objects
 at will, without having to make up silly sample data.

-To help with this, ``testtools.TestCase`` implements creation methods
called
-``getUniqueString`` and ``getUniqueInteger``.  They return strings and
-integers that are unique within the context of the test that can be used to
-assemble more complex objects.  Here's a basic example where
-``getUniqueString`` is used instead of saying "foo" or "bar" or whatever::
+To help with this, ``testtools.TestCase`` comes with an ``ObjectFactory``
that
+you can access as the ``factory`` attribute within your test
+case. ``ObjectFactory`` implements creation methods called
``getUniqueString``
+and ``getUniqueInteger``.  They return strings and integers that are unique
+within the context of the test that can be used to assemble more complex
+objects.  Here's a basic example where ``getUniqueString`` is used instead
of
+saying "foo" or "bar" or whatever::

  class SomeTest(TestCase):

      def test_full_name(self):
-          first_name = self.getUniqueString()
-          last_name = self.getUniqueString()
+          first_name = self.factory.getUniqueString()
+          last_name = self.factory.getUniqueString()
          p = Person(first_name, last_name)
          self.assertEqual(p.full_name, "%s %s" % (first_name, last_name))

@@ -1260,13 +1262,15 @@
  class TestCoupleLogic(TestCase):

      def make_arbitrary_person(self):
-          return Person(self.getUniqueString(), self.getUniqueString())
+          return Person(
+              self.factory.getUniqueString(),
+              self.factory.getUniqueString())

      def test_get_invitation(self):
          a = self.make_arbitrary_person()
          b = self.make_arbitrary_person()
          couple = Couple(a, b)
-          event_name = self.getUniqueString()
+          event_name = self.factory.getUniqueString()
          invitation = couple.get_invitation(event_name)
          self.assertEqual(
              invitation,

=== modified file 'testtools/__init__.py'
--- testtools/__init__.py       2011-09-14 10:36:41 +0000
+++ testtools/__init__.py       2011-12-15 11:18:22 +0000
@@ -12,6 +12,7 @@
    'iterate_tests',
    'MultipleExceptions',
    'MultiTestResult',
+    'ObjectFactory',
    'PlaceHolder',
    'run_test_with',
    'TestCase',
@@ -27,6 +28,7 @@
    'try_imports',
    ]

+from testtools.factory import ObjectFactory
 from testtools.helpers import (
    try_import,
    try_imports,

=== added file 'testtools/factory.py'
--- testtools/factory.py        1970-01-01 00:00:00 +0000
+++ testtools/factory.py        2011-12-15 11:18:22 +0000
@@ -0,0 +1,48 @@
+# Copyright (c) 2008-2011 testtools developers. See LICENSE for details.
+
+__all__ = [
+    'ObjectFactory',
+    ]
+
+import itertools
+
+from testtools.compat import advance_iterator
+
+# XXX: Are we happy with the name ObjectFactory?
+
+# XXX: Is this a good opportunity to change the getUniqueInteger and
+# getUniqueString methods here to be get_unique_integer and
get_unique_string?
+
+class ObjectFactory(object):
+
+    DEFAULT_PREFIX = 'unique'
+
+    def __init__(self, prefix=None):
+        if prefix is None:
+            prefix = self.DEFAULT_PREFIX
+        self._prefix = prefix
+        self._unique_id_gen = itertools.count(1)
+
+    def getUniqueInteger(self):
+        """Get an integer unique to this test.
+
+        Returns an integer that is guaranteed to be unique to this
instance.
+        Use this when you need an arbitrary integer in your test, or as a
+        helper for custom anonymous factory methods.
+        """
+        return advance_iterator(self._unique_id_gen)
+
+    def getUniqueString(self, prefix=None):
+        """Get a string unique to this test.
+
+        Returns a string that is guaranteed to be unique to this instance.
Use
+        this when you need an arbitrary string in your test, or as a helper
+        for custom anonymous factory methods.
+
+        :param prefix: The prefix of the string. If not provided, defaults
+            to the id of the tests.
+        :return: A bytestring of '<prefix>-<unique_int>'.
+        """
+        if prefix is None:
+            prefix = self._prefix
+        return '%s-%d' % (prefix, self.getUniqueInteger())

=== modified file 'testtools/testcase.py'
--- testtools/testcase.py       2011-12-05 15:21:33 +0000
+++ testtools/testcase.py       2011-12-15 11:18:22 +0000
@@ -28,6 +28,7 @@
    advance_iterator,
    reraise,
    )
+from testtools.factory import ObjectFactory
 from testtools.matchers import (
    Annotate,
    Contains,
@@ -168,7 +169,6 @@
        runTest = kwargs.pop('runTest', None)
        super(TestCase, self).__init__(*args, **kwargs)
        self._cleanups = []
-        self._unique_id_gen = itertools.count(1)
        # Generators to ensure unique traceback ids.  Maps traceback label
to
        # iterators.
        self._traceback_id_gens = {}
@@ -193,6 +193,13 @@
        if sys.version_info < (2, 6):
            # Catch old-style string exceptions with None as the instance
            self.exception_handlers.append((type(None), self._report_error))
+        # XXX: We could have a class variable factory_factory (except with
a
+        # better name) and then instead write:
+        #     self.factory = self.factory_factory(self)
+        # Which would allow others to plugin in their factories more
easily,
+        # rather than using the TestCaseWithFactory mixin pattern. Just a
+        # thought.
+        self.factory = ObjectFactory(self.id())

    def __eq__(self, other):
        eq = getattr(unittest.TestCase, '__eq__', None)
@@ -446,16 +453,20 @@
            raise _UnexpectedSuccess(reason)

    def getUniqueInteger(self):
-        """Get an integer unique to this test.
+        """DEPRECATED - Get an integer unique to this test.
+
+        Use ``self.factory.getUniqueInteger()`` instead.

        Returns an integer that is guaranteed to be unique to this instance.
        Use this when you need an arbitrary integer in your test, or as a
        helper for custom anonymous factory methods.
        """
-        return advance_iterator(self._unique_id_gen)
+        return self.factory.getUniqueInteger()

    def getUniqueString(self, prefix=None):
-        """Get a string unique to this test.
+        """DEPRECATED - Get a string unique to this test.
+
+        Use ``self.factory.getUniqueString()`` instead.

        Returns a string that is guaranteed to be unique to this instance.
Use
        this when you need an arbitrary string in your test, or as a helper
@@ -465,9 +476,7 @@
            to the id of the tests.
        :return: A bytestring of '<prefix>-<unique_int>'.
        """
-        if prefix is None:
-            prefix = self.id()
-        return '%s-%d' % (prefix, self.getUniqueInteger())
+        return self.factory.getUniqueString(prefix=prefix)

    def onException(self, exc_info, tb_label='traceback'):
        """Called when an exception propogates from test code.

=== modified file 'testtools/tests/__init__.py'
--- testtools/tests/__init__.py 2011-08-15 13:48:10 +0000
+++ testtools/tests/__init__.py 2011-12-15 11:18:22 +0000
@@ -12,6 +12,7 @@
        test_content_type,
        test_deferredruntest,
        test_distutilscmd,
+        test_factory,
        test_fixturesupport,
        test_helpers,
        test_matchers,
@@ -29,6 +30,7 @@
        test_content_type,
        test_deferredruntest,
        test_distutilscmd,
+        test_factory,
        test_fixturesupport,
        test_helpers,
        test_matchers,

=== added file 'testtools/tests/test_factory.py'
--- testtools/tests/test_factory.py     1970-01-01 00:00:00 +0000
+++ testtools/tests/test_factory.py     2011-12-15 11:18:22 +0000
@@ -0,0 +1,47 @@
+from testtools import TestCase
+from testtools.factory import ObjectFactory
+from testtools.matchers import Equals
+
+
+class TestFactory(TestCase):
+
+    def test_getUniqueInteger(self):
+        # getUniqueInteger returns an integer that increments each time you
+        # call it.
+        factory = ObjectFactory()
+        one = factory.getUniqueInteger()
+        self.assertEqual(1, one)
+        two = factory.getUniqueInteger()
+        self.assertEqual(2, two)
+
+    def test_getUniqueString_default_prefix(self):
+        # If no other parameters are given, getUniqueString returns a
string
+        # starting with the default prefix followed by a unique integer.
+        factory = ObjectFactory()
+        name_one = factory.getUniqueString()
+        self.assertEqual('%s-%d' % (factory.DEFAULT_PREFIX, 1), name_one)
+        name_two = factory.getUniqueString()
+        self.assertEqual('%s-%d' % (factory.DEFAULT_PREFIX, 2), name_two)
+
+    def test_getUniqueString_early_prefix(self):
+        # An optional prefix can be given to the factory.  If so, then all
+        # getUniqueString calls use that as a prefix by default.
+        factory = ObjectFactory(prefix=self.id())
+        name_one = factory.getUniqueString()
+        self.assertEqual('%s-%d' % (self.id(), 1), name_one)
+        name_two = factory.getUniqueString()
+        self.assertEqual('%s-%d' % (self.id(), 2), name_two)
+
+    def test_getUniqueString_late_prefix(self):
+        # If getUniqueString is given an argument, it uses that argument as
+        # the prefix of the unique string, rather than the test id.
+        factory = ObjectFactory()
+        name_one = factory.getUniqueString('foo')
+        self.assertThat(name_one, Equals('foo-1'))
+        name_two = factory.getUniqueString('bar')
+        self.assertThat(name_two, Equals('bar-2'))
+
+
+def test_suite():
+    from unittest import TestLoader
+    return TestLoader().loadTestsFromName(__name__)


_______________________________________________
Mailing list: https://launchpad.net/~testtools-dev
Post to     : testtools-dev@xxxxxxxxxxxxxxxxxxx
Unsubscribe : https://launchpad.net/~testtools-dev
More help   : https://help.launchpad.net/ListHelp

-- 
https://code.launchpad.net/~jml/testtools/extract-factory/+merge/85833
Your team testtools developers is subscribed to branch lp:testtools.


Follow ups

References