#30249: Deprecate re-raising view exceptions from test client in tests
-------------------------------------+-------------------------------------
     Reporter:  Jon Dufresne         |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |
    Component:  Testing framework    |                  Version:  master
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Jon Dufresne):

 Hi Carlton, thanks for the response.

 > It's both longer ...

 If you feel this is a matter of ergonomics, then I'm happy to add a helper
 assert method. Something this like `assertResponseException` such that

 {{{
 response = self.client.get('/detail/author/invalid/qs/')
 self.assertEqual(response.status_code, 500)
 _, exc_value, _ = response.exc_info
 self.assertIsInstance(exc_value, ImproperlyConfigured)
 self.assertEqual(str(exc_value), msg)
 }}}

 Becomes:

 {{{
 response = self.client.get('/detail/author/invalid/qs/')
 self.assertResponseException(response, response, msg)
 }}}

 I could then document it and use it throughout the Django test suite.
 WDYT?

 > ... and less clear in intent.

 IMO, the previous version is less clear of the ''actual behavior'' under
 test. If I didn't already know how the Django test client works, when
 reading:

 {{{
 with self.assertRaisesMessage(ImproperlyConfigured, msg):
     self.client.get('/detail/author/invalid/qs/')
 }}}

 Upon first read (again, if I didn't already know how the Django test
 client works) this leads me to believe that making a GET request on the
 provided URL results in an '''unhandled''' exception. However, this is not
 the case. The exception is handled by the default error handler,
 `django.core.handlers.exception.handle_uncaught_exception` and a 500
 response is returned. Obviously, this is wrong as the test client has
 modified the code under test to make it appear as if the exception is
 unhandled. IMO, it is normally bad practice to modify the code under test
 unless testing for a very specific implementation detail. It should not be
 the default state of testing. Instead, we should be testing code as close
 to production as reasonable. By modifying the code under test, we've
 slightly moved away from the production code.

 > Raising the exception is a great behaviour in most cases. It's a great
 default behaviour.

 Normally, I agree. But keep in mind, we're in the context of a test.
 ''Something'' will be asserted after the middleware + view executes
 (otherwise, what's the point of the test?) It could even be something as
 simple as `self.assertEqual(response.status_code, 200)`. In the event of
 an unwanted view exception, these assertions will fail.

 If you prefer the re-raising of exceptions for your project, then you can
 and should set the existing setting `DEBUG_PROPAGATE_EXCEPTIONS` to `True`
 in the test's `settings.py`. Then, the old behavior will be restored to
 eagerly throw exceptions.

 I've created an alternate form of the PR with this set during Django's
 test suite here:

 https://github.com/django/django/compare/master...jdufresne:raise-request-
 exception-default-on

 As you can see, this version has many fewer adjustments to tests. If this
 version is more agreeable, I'm happy to replace the PR with it.

 > The @override_settings(DEBUG_PROPAGATE_EXCEPTIONS=False) is bad API.

 This setting already exits. I didn't invent it. It is documented here:
 https://docs.djangoproject.com/en/2.1/ref/settings/#debug-propagate-
 exceptions

 I don't care much for this setting on its own, I only noticed that it
 already existed so I didn't invent a new mechanism. Having multiple ways
 to re-raise request exceptions seems unnecessary to me. I've never used it
 prior to this PR.

 > Beyond all that I don't think it's worth the churn.

 To be clear, this isn't about churn. It is about moving the test client
 closer to simulating a real world HTTP client by avoiding modifying code
 under test, which I believe will result in more productive tests.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30249#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.05564a891b942810175f77c1f46ceed8%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to