PageRenderTime 208ms CodeModel.GetById 71ms app.highlight 97ms RepoModel.GetById 34ms app.codeStats 1ms

/tests/modeltests/test_client/models.py

https://code.google.com/p/mango-py/
Python | 490 lines | 448 code | 14 blank | 28 comment | 3 complexity | 442cf751ad572ccad3288b2983571428 MD5 | raw file
  1# coding: utf-8
  2"""
  339. Testing using the Test Client
  4
  5The test client is a class that can act like a simple
  6browser for testing purposes.
  7
  8It allows the user to compose GET and POST requests, and
  9obtain the response that the server gave to those requests.
 10The server Response objects are annotated with the details
 11of the contexts and templates that were rendered during the
 12process of serving the request.
 13
 14``Client`` objects are stateful - they will retain cookie (and
 15thus session) details for the lifetime of the ``Client`` instance.
 16
 17This is not intended as a replacement for Twill, Selenium, or
 18other browser automation frameworks - it is here to allow
 19testing against the contexts and templates produced by a view,
 20rather than the HTML rendered to the end-user.
 21
 22"""
 23from django.conf import settings
 24from django.core import mail
 25from django.test import Client, TestCase, RequestFactory
 26
 27from views import get_view
 28
 29
 30class ClientTest(TestCase):
 31    fixtures = ['testdata.json']
 32
 33    def test_get_view(self):
 34        "GET a view"
 35        # The data is ignored, but let's check it doesn't crash the system
 36        # anyway.
 37        data = {'var': u'\xf2'}
 38        response = self.client.get('/test_client/get_view/', data)
 39
 40        # Check some response details
 41        self.assertContains(response, 'This is a test')
 42        self.assertEqual(response.context['var'], u'\xf2')
 43        self.assertEqual(response.templates[0].name, 'GET Template')
 44
 45    def test_get_post_view(self):
 46        "GET a view that normally expects POSTs"
 47        response = self.client.get('/test_client/post_view/', {})
 48
 49        # Check some response details
 50        self.assertEqual(response.status_code, 200)
 51        self.assertEqual(response.templates[0].name, 'Empty GET Template')
 52        self.assertTemplateUsed(response, 'Empty GET Template')
 53        self.assertTemplateNotUsed(response, 'Empty POST Template')
 54
 55    def test_empty_post(self):
 56        "POST an empty dictionary to a view"
 57        response = self.client.post('/test_client/post_view/', {})
 58
 59        # Check some response details
 60        self.assertEqual(response.status_code, 200)
 61        self.assertEqual(response.templates[0].name, 'Empty POST Template')
 62        self.assertTemplateNotUsed(response, 'Empty GET Template')
 63        self.assertTemplateUsed(response, 'Empty POST Template')
 64
 65    def test_post(self):
 66        "POST some data to a view"
 67        post_data = {
 68            'value': 37
 69        }
 70        response = self.client.post('/test_client/post_view/', post_data)
 71
 72        # Check some response details
 73        self.assertEqual(response.status_code, 200)
 74        self.assertEqual(response.context['data'], '37')
 75        self.assertEqual(response.templates[0].name, 'POST Template')
 76        self.assertTrue('Data received' in response.content)
 77
 78    def test_response_headers(self):
 79        "Check the value of HTTP headers returned in a response"
 80        response = self.client.get("/test_client/header_view/")
 81
 82        self.assertEqual(response['X-DJANGO-TEST'], 'Slartibartfast')
 83
 84    def test_raw_post(self):
 85        "POST raw data (with a content type) to a view"
 86        test_doc = """<?xml version="1.0" encoding="utf-8"?><library><book><title>Blink</title><author>Malcolm Gladwell</author></book></library>"""
 87        response = self.client.post("/test_client/raw_post_view/", test_doc,
 88                                    content_type="text/xml")
 89        self.assertEqual(response.status_code, 200)
 90        self.assertEqual(response.templates[0].name, "Book template")
 91        self.assertEqual(response.content, "Blink - Malcolm Gladwell")
 92
 93    def test_redirect(self):
 94        "GET a URL that redirects elsewhere"
 95        response = self.client.get('/test_client/redirect_view/')
 96        # Check that the response was a 302 (redirect) and that
 97        # assertRedirect() understands to put an implicit http://testserver/ in
 98        # front of non-absolute URLs.
 99        self.assertRedirects(response, '/test_client/get_view/')
100
101        host = 'django.testserver'
102        client_providing_host = Client(HTTP_HOST=host)
103        response = client_providing_host.get('/test_client/redirect_view/')
104        # Check that the response was a 302 (redirect) with absolute URI
105        self.assertRedirects(response, '/test_client/get_view/', host=host)
106
107    def test_redirect_with_query(self):
108        "GET a URL that redirects with given GET parameters"
109        response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
110
111        # Check if parameters are intact
112        self.assertRedirects(response, 'http://testserver/test_client/get_view/?var=value')
113
114    def test_permanent_redirect(self):
115        "GET a URL that redirects permanently elsewhere"
116        response = self.client.get('/test_client/permanent_redirect_view/')
117        # Check that the response was a 301 (permanent redirect)
118        self.assertRedirects(response, 'http://testserver/test_client/get_view/', status_code=301)
119
120        client_providing_host = Client(HTTP_HOST='django.testserver')
121        response = client_providing_host.get('/test_client/permanent_redirect_view/')
122        # Check that the response was a 301 (permanent redirect) with absolute URI
123        self.assertRedirects(response, 'http://django.testserver/test_client/get_view/', status_code=301)
124
125    def test_temporary_redirect(self):
126        "GET a URL that does a non-permanent redirect"
127        response = self.client.get('/test_client/temporary_redirect_view/')
128        # Check that the response was a 302 (non-permanent redirect)
129        self.assertRedirects(response, 'http://testserver/test_client/get_view/', status_code=302)
130
131    def test_redirect_to_strange_location(self):
132        "GET a URL that redirects to a non-200 page"
133        response = self.client.get('/test_client/double_redirect_view/')
134
135        # Check that the response was a 302, and that
136        # the attempt to get the redirection location returned 301 when retrieved
137        self.assertRedirects(response, 'http://testserver/test_client/permanent_redirect_view/', target_status_code=301)
138
139    def test_follow_redirect(self):
140        "A URL that redirects can be followed to termination."
141        response = self.client.get('/test_client/double_redirect_view/', follow=True)
142        self.assertRedirects(response, 'http://testserver/test_client/get_view/', status_code=302, target_status_code=200)
143        self.assertEqual(len(response.redirect_chain), 2)
144
145    def test_redirect_http(self):
146        "GET a URL that redirects to an http URI"
147        response = self.client.get('/test_client/http_redirect_view/',follow=True)
148        self.assertFalse(response.test_was_secure_request)
149
150    def test_redirect_https(self):
151        "GET a URL that redirects to an https URI"
152        response = self.client.get('/test_client/https_redirect_view/',follow=True)
153        self.assertTrue(response.test_was_secure_request)
154
155    def test_notfound_response(self):
156        "GET a URL that responds as '404:Not Found'"
157        response = self.client.get('/test_client/bad_view/')
158
159        # Check that the response was a 404, and that the content contains MAGIC
160        self.assertContains(response, 'MAGIC', status_code=404)
161
162    def test_valid_form(self):
163        "POST valid data to a form"
164        post_data = {
165            'text': 'Hello World',
166            'email': 'foo@example.com',
167            'value': 37,
168            'single': 'b',
169            'multi': ('b','c','e')
170        }
171        response = self.client.post('/test_client/form_view/', post_data)
172        self.assertEqual(response.status_code, 200)
173        self.assertTemplateUsed(response, "Valid POST Template")
174
175    def test_valid_form_with_hints(self):
176        "GET a form, providing hints in the GET data"
177        hints = {
178            'text': 'Hello World',
179            'multi': ('b','c','e')
180        }
181        response = self.client.get('/test_client/form_view/', data=hints)
182        self.assertEqual(response.status_code, 200)
183        self.assertTemplateUsed(response, "Form GET Template")
184        # Check that the multi-value data has been rolled out ok
185        self.assertContains(response, 'Select a valid choice.', 0)
186
187    def test_incomplete_data_form(self):
188        "POST incomplete data to a form"
189        post_data = {
190            'text': 'Hello World',
191            'value': 37
192        }
193        response = self.client.post('/test_client/form_view/', post_data)
194        self.assertContains(response, 'This field is required.', 3)
195        self.assertEqual(response.status_code, 200)
196        self.assertTemplateUsed(response, "Invalid POST Template")
197
198        self.assertFormError(response, 'form', 'email', 'This field is required.')
199        self.assertFormError(response, 'form', 'single', 'This field is required.')
200        self.assertFormError(response, 'form', 'multi', 'This field is required.')
201
202    def test_form_error(self):
203        "POST erroneous data to a form"
204        post_data = {
205            'text': 'Hello World',
206            'email': 'not an email address',
207            'value': 37,
208            'single': 'b',
209            'multi': ('b','c','e')
210        }
211        response = self.client.post('/test_client/form_view/', post_data)
212        self.assertEqual(response.status_code, 200)
213        self.assertTemplateUsed(response, "Invalid POST Template")
214
215        self.assertFormError(response, 'form', 'email', 'Enter a valid e-mail address.')
216
217    def test_valid_form_with_template(self):
218        "POST valid data to a form using multiple templates"
219        post_data = {
220            'text': 'Hello World',
221            'email': 'foo@example.com',
222            'value': 37,
223            'single': 'b',
224            'multi': ('b','c','e')
225        }
226        response = self.client.post('/test_client/form_view_with_template/', post_data)
227        self.assertContains(response, 'POST data OK')
228        self.assertTemplateUsed(response, "form_view.html")
229        self.assertTemplateUsed(response, 'base.html')
230        self.assertTemplateNotUsed(response, "Valid POST Template")
231
232    def test_incomplete_data_form_with_template(self):
233        "POST incomplete data to a form using multiple templates"
234        post_data = {
235            'text': 'Hello World',
236            'value': 37
237        }
238        response = self.client.post('/test_client/form_view_with_template/', post_data)
239        self.assertContains(response, 'POST data has errors')
240        self.assertTemplateUsed(response, 'form_view.html')
241        self.assertTemplateUsed(response, 'base.html')
242        self.assertTemplateNotUsed(response, "Invalid POST Template")
243
244        self.assertFormError(response, 'form', 'email', 'This field is required.')
245        self.assertFormError(response, 'form', 'single', 'This field is required.')
246        self.assertFormError(response, 'form', 'multi', 'This field is required.')
247
248    def test_form_error_with_template(self):
249        "POST erroneous data to a form using multiple templates"
250        post_data = {
251            'text': 'Hello World',
252            'email': 'not an email address',
253            'value': 37,
254            'single': 'b',
255            'multi': ('b','c','e')
256        }
257        response = self.client.post('/test_client/form_view_with_template/', post_data)
258        self.assertContains(response, 'POST data has errors')
259        self.assertTemplateUsed(response, "form_view.html")
260        self.assertTemplateUsed(response, 'base.html')
261        self.assertTemplateNotUsed(response, "Invalid POST Template")
262
263        self.assertFormError(response, 'form', 'email', 'Enter a valid e-mail address.')
264
265    def test_unknown_page(self):
266        "GET an invalid URL"
267        response = self.client.get('/test_client/unknown_view/')
268
269        # Check that the response was a 404
270        self.assertEqual(response.status_code, 404)
271
272    def test_url_parameters(self):
273        "Make sure that URL ;-parameters are not stripped."
274        response = self.client.get('/test_client/unknown_view/;some-parameter')
275
276        # Check that the path in the response includes it (ignore that it's a 404)
277        self.assertEqual(response.request['PATH_INFO'], '/test_client/unknown_view/;some-parameter')
278
279    def test_view_with_login(self):
280        "Request a page that is protected with @login_required"
281
282        # Get the page without logging in. Should result in 302.
283        response = self.client.get('/test_client/login_protected_view/')
284        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_view/')
285
286        # Log in
287        login = self.client.login(username='testclient', password='password')
288        self.assertTrue(login, 'Could not log in')
289
290        # Request a page that requires a login
291        response = self.client.get('/test_client/login_protected_view/')
292        self.assertEqual(response.status_code, 200)
293        self.assertEqual(response.context['user'].username, 'testclient')
294
295    def test_view_with_method_login(self):
296        "Request a page that is protected with a @login_required method"
297
298        # Get the page without logging in. Should result in 302.
299        response = self.client.get('/test_client/login_protected_method_view/')
300        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_method_view/')
301
302        # Log in
303        login = self.client.login(username='testclient', password='password')
304        self.assertTrue(login, 'Could not log in')
305
306        # Request a page that requires a login
307        response = self.client.get('/test_client/login_protected_method_view/')
308        self.assertEqual(response.status_code, 200)
309        self.assertEqual(response.context['user'].username, 'testclient')
310
311    def test_view_with_login_and_custom_redirect(self):
312        "Request a page that is protected with @login_required(redirect_field_name='redirect_to')"
313
314        # Get the page without logging in. Should result in 302.
315        response = self.client.get('/test_client/login_protected_view_custom_redirect/')
316        self.assertRedirects(response, 'http://testserver/accounts/login/?redirect_to=/test_client/login_protected_view_custom_redirect/')
317
318        # Log in
319        login = self.client.login(username='testclient', password='password')
320        self.assertTrue(login, 'Could not log in')
321
322        # Request a page that requires a login
323        response = self.client.get('/test_client/login_protected_view_custom_redirect/')
324        self.assertEqual(response.status_code, 200)
325        self.assertEqual(response.context['user'].username, 'testclient')
326
327    def test_view_with_bad_login(self):
328        "Request a page that is protected with @login, but use bad credentials"
329
330        login = self.client.login(username='otheruser', password='nopassword')
331        self.assertFalse(login)
332
333    def test_view_with_inactive_login(self):
334        "Request a page that is protected with @login, but use an inactive login"
335
336        login = self.client.login(username='inactive', password='password')
337        self.assertFalse(login)
338
339    def test_logout(self):
340        "Request a logout after logging in"
341        # Log in
342        self.client.login(username='testclient', password='password')
343
344        # Request a page that requires a login
345        response = self.client.get('/test_client/login_protected_view/')
346        self.assertEqual(response.status_code, 200)
347        self.assertEqual(response.context['user'].username, 'testclient')
348
349        # Log out
350        self.client.logout()
351
352        # Request a page that requires a login
353        response = self.client.get('/test_client/login_protected_view/')
354        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_view/')
355
356    def test_view_with_permissions(self):
357        "Request a page that is protected with @permission_required"
358
359        # Get the page without logging in. Should result in 302.
360        response = self.client.get('/test_client/permission_protected_view/')
361        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
362
363        # Log in
364        login = self.client.login(username='testclient', password='password')
365        self.assertTrue(login, 'Could not log in')
366
367        # Log in with wrong permissions. Should result in 302.
368        response = self.client.get('/test_client/permission_protected_view/')
369        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
370
371        # TODO: Log in with right permissions and request the page again
372
373    def test_view_with_method_permissions(self):
374        "Request a page that is protected with a @permission_required method"
375
376        # Get the page without logging in. Should result in 302.
377        response = self.client.get('/test_client/permission_protected_method_view/')
378        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
379
380        # Log in
381        login = self.client.login(username='testclient', password='password')
382        self.assertTrue(login, 'Could not log in')
383
384        # Log in with wrong permissions. Should result in 302.
385        response = self.client.get('/test_client/permission_protected_method_view/')
386        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
387
388        # TODO: Log in with right permissions and request the page again
389
390    def test_session_modifying_view(self):
391        "Request a page that modifies the session"
392        # Session value isn't set initially
393        try:
394            self.client.session['tobacconist']
395            self.fail("Shouldn't have a session value")
396        except KeyError:
397            pass
398
399        from django.contrib.sessions.models import Session
400        response = self.client.post('/test_client/session_view/')
401
402        # Check that the session was modified
403        self.assertEqual(self.client.session['tobacconist'], 'hovercraft')
404
405    def test_view_with_exception(self):
406        "Request a page that is known to throw an error"
407        self.assertRaises(KeyError, self.client.get, "/test_client/broken_view/")
408
409        #Try the same assertion, a different way
410        try:
411            self.client.get('/test_client/broken_view/')
412            self.fail('Should raise an error')
413        except KeyError:
414            pass
415
416    def test_mail_sending(self):
417        "Test that mail is redirected to a dummy outbox during test setup"
418
419        response = self.client.get('/test_client/mail_sending_view/')
420        self.assertEqual(response.status_code, 200)
421
422        self.assertEqual(len(mail.outbox), 1)
423        self.assertEqual(mail.outbox[0].subject, 'Test message')
424        self.assertEqual(mail.outbox[0].body, 'This is a test email')
425        self.assertEqual(mail.outbox[0].from_email, 'from@example.com')
426        self.assertEqual(mail.outbox[0].to[0], 'first@example.com')
427        self.assertEqual(mail.outbox[0].to[1], 'second@example.com')
428
429    def test_mass_mail_sending(self):
430        "Test that mass mail is redirected to a dummy outbox during test setup"
431
432        response = self.client.get('/test_client/mass_mail_sending_view/')
433        self.assertEqual(response.status_code, 200)
434
435        self.assertEqual(len(mail.outbox), 2)
436        self.assertEqual(mail.outbox[0].subject, 'First Test message')
437        self.assertEqual(mail.outbox[0].body, 'This is the first test email')
438        self.assertEqual(mail.outbox[0].from_email, 'from@example.com')
439        self.assertEqual(mail.outbox[0].to[0], 'first@example.com')
440        self.assertEqual(mail.outbox[0].to[1], 'second@example.com')
441
442        self.assertEqual(mail.outbox[1].subject, 'Second Test message')
443        self.assertEqual(mail.outbox[1].body, 'This is the second test email')
444        self.assertEqual(mail.outbox[1].from_email, 'from@example.com')
445        self.assertEqual(mail.outbox[1].to[0], 'second@example.com')
446        self.assertEqual(mail.outbox[1].to[1], 'third@example.com')
447
448class CSRFEnabledClientTests(TestCase):
449    def setUp(self):
450        # Enable the CSRF middleware for this test
451        self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES
452        csrf_middleware_class = 'django.middleware.csrf.CsrfViewMiddleware'
453        if csrf_middleware_class not in settings.MIDDLEWARE_CLASSES:
454            settings.MIDDLEWARE_CLASSES += (csrf_middleware_class,)
455
456    def tearDown(self):
457        settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES
458
459    def test_csrf_enabled_client(self):
460        "A client can be instantiated with CSRF checks enabled"
461        csrf_client = Client(enforce_csrf_checks=True)
462
463        # The normal client allows the post
464        response = self.client.post('/test_client/post_view/', {})
465        self.assertEqual(response.status_code, 200)
466
467        # The CSRF-enabled client rejects it
468        response = csrf_client.post('/test_client/post_view/', {})
469        self.assertEqual(response.status_code, 403)
470
471
472class CustomTestClient(Client):
473    i_am_customized = "Yes"
474
475class CustomTestClientTest(TestCase):
476    client_class = CustomTestClient
477
478    def test_custom_test_client(self):
479        """A test case can specify a custom class for self.client."""
480        self.assertEqual(hasattr(self.client, "i_am_customized"), True)
481
482
483class RequestFactoryTest(TestCase):
484    def test_request_factory(self):
485        factory = RequestFactory()
486        request = factory.get('/somewhere/')
487        response = get_view(request)
488
489        self.assertEqual(response.status_code, 200)
490        self.assertContains(response, 'This is a test')