Index: django/test/testcases.py
===================================================================
--- django/test/testcases.py	(revision 6248)
+++ django/test/testcases.py	(working copy)
@@ -1,4 +1,7 @@
+import random
 import re
+import sys
+import types
 import unittest
 from urlparse import urlsplit
 
@@ -11,6 +14,30 @@
 
 normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
 
+def generate_fuzzy_value(value_type):
+    """
+    Returns a randome value of the specified type, or raises a ValueError if
+    the type is not supported. If value_type is callable then it is called and
+    its return value is returned. This allows you to specify a function that
+    generates a random value of a type that isn't supported.
+    """
+    if value_type is None or issubclass(value_type, types.NoneType):
+        return None
+    if issubclass(value_type, types.BooleanType):
+        return random.choice((True, False))
+    if issubclass(value_type, types.IntType):
+        return random.randint(-sys.maxint - 1, sys.maxint)
+    if issubclass(value_type, types.LongType):
+        return long(generate_fuzzy_value(int) * generate_fuzzy_value(int))
+    if issubclass(value_type, types.FloatType):
+        return random.random() * generate_fuzzy_value(int)
+    if issubclass(value_type, basestring):
+        length = random.randint(0, 1000)
+        return u''.join([unichr(random.randint(32, 65534)) for i in range(length)])
+    if callable(value_type):
+        return value_type()
+    raise ValueError("Unsupported type: %s" % value_type)
+
 def to_list(value):
     """
     Puts value into a list if it's not already one.
@@ -186,3 +213,72 @@
         self.failIf(template_name in template_names,
             (u"Template '%s' was used unexpectedly in rendering the"
              u" response") % template_name)
+
+    def assertModelUnicodePassesFuzzTest(self, model, repeat=10):
+        """
+        Asserts that after having assigned random unicode data into each of 
+        the fields of an instance of the specified model that calling the
+        __unicode__ method of the instance doesn't raise a UnicodeError.
+        Random data is assigned and the __unicode__ method called repeat times.
+        """
+        instance = model()
+        opts = model._meta
+        for i in range(repeat):
+            for field in opts.fields:
+                setattr(instance, field.name, generate_fuzzy_value(str))
+            try:
+                unicode(instance)
+            except UnicodeError, e:
+                self.fail(u"Model '%s' unexpectedly raised %s when converting to unicode: %s" %
+                    (model.__name__, e.__class__.__name__, e))
+
+    def assertFunctionPassesFuzzTest(self, func, arg_types=(), 
+        permitted_return_types=(), permitted_exceptions=(), repeat=10):
+        """
+        Asserts that the function when called with random values of the types
+        specified by arg_types that the return value has a type from
+        permitted_return_types and that if an exception is raised it is one
+        that is in permitted_exceptions. The function is called repeat times
+        with random data.
+        """
+        
+        def isiterable(o):
+            try:
+                iter(o)
+            except TypeError:
+                return False
+            return True
+        
+        def cartesian_product(L, *lists):
+            if not lists:
+                for x in L:
+                    yield (x,)
+            else:
+                for x in L:
+                    for y in cartesian_product(lists[0], *lists[1:]):
+                        yield (x,) + y
+
+        # Allow the use of None instead of types.NoneType
+        if None in permitted_return_types and types.NoneType not in permitted_return_types:
+            permitted_return_types = tuple(permitted_return_types)
+            permitted_return_types += (types.NoneType,)
+
+        # Ensure arg_types is a sequence of iterables
+        for i, arg_type in enumerate(arg_types):
+            if not isiterable(arg_type): arg_types[i] = [arg_type]
+        
+        for i in range(repeat):
+            for atypes in cartesian_product(*arg_types):
+                args = []
+                for arg_type in atypes:
+                    args.append(generate_fuzzy_value(arg_type))
+                try:
+                    return_value = func(*args)
+                except:
+                    if permitted_exceptions:
+                        exc_type, exc_value = sys.exc_info()[:2]
+                        if exc_type not in permitted_exceptions:
+                            self.fail(u"Unexpected %s encountered when calling %s with inputs %r: %s" % (exc_type.__name__, func.__name__, args, exc_value))
+                else:
+                    if permitted_return_types and type(return_value) not in permitted_return_types:
+                        self.fail(u"Unexpected return value type %s encountered when calling %s with inputs %r." % (return_value.__name__, func.__name__, args))
\ No newline at end of file
