I found some time this evening to work this out, and have included a
revised patch for this proposal at the end of this message.

I tried to keep changes to an absolute minimum, but here are a few
notes about the changes and decisions I did make:

* The addition of this feature required what I imagine to be a
significant change to test suite runner. Namely, I switched the order
of the build_suite() and setup_test_environment() methods in
run_tests(). The reason for this has to do with what i suggested in my
earlier reply in this thread, namely that there isn't a feasible way
to connect to the signals from application code until after
applications have been imported. I also wanted to attempt to implement
Russ's suggestion of having Django itself use the signals for setup
and teardown. The most logical and clean way to do this (and the only
way to organize things such that Django could use the code) was to
construct the run_test() sequence such that test suites are first
built, then setup, then run tests, then teardown. The Django tests
suite passed when the order was inverted, but I am quite certain it is
a huge assumption on my part that the order can be switched here. Does
anybody have any opinions on this, or reasonings as to why the
setup_test_environment() stuff would need to be called before
build_suite()? I imagine this would be the greatest concern with my
proposed patch.

* The test utility methods setup_test_environment() and
teardown_test_environment() are now connected to the respective
signals and are executed when those emit, rather than being called
directly from the test suite runner. The **kwargs was added to their
signature so that the they could be executed via the signal.

* Aside from adding the code to create the signals and to emit them in
the test runner, that's all the changes that were necessary to
implement this feature.

* I have included documentation changes in the patch in what is
hopefully a tolerable first stab.

I welcome any additional feedback or suggestions. Provided there are
no serious objections or deal breakers pointed out in this discussion,
I'll submit a ticket for this, which I assume is the best way to move
it forward in the official discussion and review process.

Here's my revised proposed patch:


Index: django/test/simple.py
===================================================================
--- django/test/simple.py       (revision 13861)
+++ django/test/simple.py       (working copy)
@@ -7,6 +7,7 @@
 from django.test import _doctest as doctest
 from django.test.utils import setup_test_environment,
teardown_test_environment
 from django.test.testcases import OutputChecker, DocTestRunner,
TestCase
+from django.test.signals import test_setup, test_teardown

 # The module name for tests outside models.py
 TEST_MODULE = 'tests'
@@ -230,7 +231,7 @@
         self.failfast = failfast

     def setup_test_environment(self, **kwargs):
-        setup_test_environment()
+        test_setup.send(sender=self)
         settings.DEBUG = False

     def build_suite(self, test_labels, extra_tests=None, **kwargs):
@@ -284,7 +285,7 @@
             connection.creation.destroy_test_db(old_name,
self.verbosity)

     def teardown_test_environment(self, **kwargs):
-        teardown_test_environment()
+        test_teardown.send(sender=self)

     def suite_result(self, suite, result, **kwargs):
         return len(result.failures) + len(result.errors)
@@ -308,8 +309,8 @@

         Returns the number of tests that failed.
         """
+        suite = self.build_suite(test_labels, extra_tests)
         self.setup_test_environment()
-        suite = self.build_suite(test_labels, extra_tests)
         old_config = self.setup_databases()
         result = self.run_suite(suite)
         self.teardown_databases(old_config)
Index: django/test/signals.py
===================================================================
--- django/test/signals.py      (revision 13861)
+++ django/test/signals.py      (working copy)
@@ -1,3 +1,5 @@
 from django.dispatch import Signal

 template_rendered = Signal(providing_args=["template", "context"])
+test_setup = Signal()
+test_teardown = Signal()
\ No newline at end of file
Index: django/test/utils.py
===================================================================
--- django/test/utils.py        (revision 13861)
+++ django/test/utils.py        (working copy)
@@ -52,7 +52,7 @@
     return self.nodelist.render(context)


-def setup_test_environment():
+def setup_test_environment(**kwargs):
     """Perform any global pre-test setup. This involves:

         - Installing the instrumented test renderer
@@ -71,8 +71,9 @@
     mail.outbox = []

     deactivate()
+signals.test_setup.connect(setup_test_environment)

-def teardown_test_environment():
+def teardown_test_environment(**kwargs):
     """Perform any global post-test teardown. This involves:

         - Restoring the original test renderer
@@ -89,6 +90,7 @@
     del mail.original_email_backend

     del mail.outbox
+signals.test_teardown.connect(teardown_test_environment)

 def get_runner(settings):
     test_path = settings.TEST_RUNNER.split('.')
Index: docs/ref/signals.txt
===================================================================
--- docs/ref/signals.txt        (revision 13861)
+++ docs/ref/signals.txt        (working copy)
@@ -455,6 +455,39 @@
         The :class:`~django.template.Context` with which the template
was
         rendered.

+test_setup
+----------
+
+.. data:: django.test.signals.test_setup
+   :module:
+
+.. versionadded:: 1.3
+
+Sent during global pre-test setup, just after applications have
loaded and
+the test suite has been built. This signal is not emitted during
normal
+operation.
+
+Arguments sent with this signal:
+
+    sender
+        The :class:`~django.test.simple.DjangoTestSuiteRunner`
object.
+
+test_teardown
+-------------
+
+.. data:: django.test.signals.test_teardown
+   :module:
+
+.. versionadded:: 1.3
+
+Sent during global post-test breakdown. This signal is not emitted
during
+normal operation.
+
+Arguments sent with this signal:
+
+    sender
+        The :class:`~django.test.simple.DjangoTestSuiteRunner`
object.
+
 Database Wrappers
 =================

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to