New upstream version 0.8.0
Nilesh Patra
3 years ago
0 | 0 | Metadata-Version: 1.1 |
1 | 1 | Name: Flask-Testing |
2 | Version: 0.4.2 | |
2 | Version: 0.8.0 | |
3 | 3 | Summary: Unit testing for Flask |
4 | 4 | Home-page: https://github.com/jarus/flask-testing |
5 | 5 | Author: Dan Jacob |
0 | 0 | Metadata-Version: 1.1 |
1 | 1 | Name: Flask-Testing |
2 | Version: 0.4.2 | |
2 | Version: 0.8.0 | |
3 | 3 | Summary: Unit testing for Flask |
4 | 4 | Home-page: https://github.com/jarus/flask-testing |
5 | 5 | Author: Dan Jacob |
0 | Flask-Testing | |
0 | flask-testing | |
1 | 1 | |
2 | 2 | Unit testing support for Flask. |
3 | 3 | |
4 | 4 | For full information please refer to the online docs: |
5 | 5 | |
6 | http://packages.python.org/Flask-Testing | |
6 | https://flask-testing.readthedocs.io/en/latest/ |
Binary diff not shown
25 | 25 | |
26 | 26 | Simply subclass the ``TestCase`` class:: |
27 | 27 | |
28 | from flask.ext.testing import TestCase | |
28 | from flask_testing import TestCase | |
29 | 29 | |
30 | 30 | class MyTest(TestCase): |
31 | 31 | |
35 | 35 | You must specify the ``create_app`` method, which should return a Flask instance:: |
36 | 36 | |
37 | 37 | from flask import Flask |
38 | from flask.ext.testing import TestCase | |
38 | from flask_testing import TestCase | |
39 | 39 | |
40 | 40 | class MyTest(TestCase): |
41 | 41 | |
56 | 56 | |
57 | 57 | import urllib2 |
58 | 58 | from flask import Flask |
59 | from flask.ext.testing import LiveServerTestCase | |
59 | from flask_testing import LiveServerTestCase | |
60 | 60 | |
61 | 61 | class MyTest(LiveServerTestCase): |
62 | 62 | |
65 | 65 | app.config['TESTING'] = True |
66 | 66 | # Default port is 5000 |
67 | 67 | app.config['LIVESERVER_PORT'] = 8943 |
68 | # Default timeout is 5 seconds | |
69 | app.config['LIVESERVER_TIMEOUT'] = 10 | |
68 | 70 | return app |
69 | 71 | |
70 | 72 | def test_server_is_up_and_running(self): |
72 | 74 | self.assertEqual(response.code, 200) |
73 | 75 | |
74 | 76 | The method ``get_server_url`` will return http://localhost:8943 in this case. |
77 | ||
78 | ||
79 | Dynamic LiveServerTestCase port | |
80 | ------------------------------- | |
81 | ||
82 | By default, ``LiveServerTestCase`` will use the pre-defined port for running the live server. If | |
83 | multiple tests need to run in parallel, the ``LIVESERVER_PORT`` can be set to ``0`` to have the | |
84 | underlying operating system pick an open port for the server. The full address of the running | |
85 | server can be accessed via the ``get_server_url`` call on the test case:: | |
86 | ||
87 | ||
88 | import urllib2 | |
89 | from flask import Flask | |
90 | from flask_testing import LiveServerTestCase | |
91 | ||
92 | class MyTest(LiveServerTestCase): | |
93 | ||
94 | def create_app(self): | |
95 | app = Flask(__name__) | |
96 | app.config['TESTING'] = True | |
97 | ||
98 | # Set to 0 to have the OS pick the port. | |
99 | app.config['LIVESERVER_PORT'] = 0 | |
100 | ||
101 | return app | |
102 | ||
103 | def test_server_is_up_and_running(self): | |
104 | response = urllib2.urlopen(self.get_server_url()) | |
105 | self.assertEqual(response.code, 200) | |
75 | 106 | |
76 | 107 | |
77 | 108 | Testing JSON responses |
149 | 180 | First, ensure you set the database URI to something other than your production database ! Second, |
150 | 181 | it's usually a good idea to create and drop your tables with each test run, to ensure clean tests:: |
151 | 182 | |
152 | from flask.ext.testing import TestCase | |
183 | from flask_testing import TestCase | |
153 | 184 | |
154 | 185 | from myapp import create_app, db |
155 | 186 | |
214 | 245 | with unittest |
215 | 246 | ------------- |
216 | 247 | |
217 | For the beginning I go on the theory that you put all your tests into one file | |
218 | than you can use the :func:`unittest.main` function. This function will discover | |
219 | all your test methods in your :class:`TestCase` classes. Remember, the test | |
220 | methods and classes must starts with ``test`` (case-insensitive) that they will | |
221 | discover. | |
248 | I recommend you to put all your tests into one file so that you can use | |
249 | the :func:`unittest.main` function. This function will discover all your test | |
250 | methods in your :class:`TestCase` classes. Remember, the names of the test | |
251 | methods and classes must start with ``test`` (case-insensitive) so that | |
252 | they can be discovered. | |
222 | 253 | |
223 | 254 | An example test file could look like this:: |
224 | 255 | |
225 | 256 | import unittest |
226 | import flask.ext.testing | |
257 | import flask_testing | |
227 | 258 | |
228 | 259 | # your test cases |
229 | 260 | |
239 | 270 | |
240 | 271 | Changes |
241 | 272 | ======= |
273 | ||
274 | 0.8.0 (05.03.2020) | |
275 | ------------------ | |
276 | ||
277 | * Drops support for python 2.6, 3.3, and 3.4 due to end-of-life. | |
278 | * Fixes werkzeug 1.0 compatibility issue with import paths | |
279 | ||
280 | 0.7.1 (19.12.2017) | |
281 | ------------------ | |
282 | ||
283 | * Reverts the request context changes from ``0.7.0``. This change broke | |
284 | backwards compatibility so it will be moved to a major version release | |
285 | instead. | |
286 | ||
287 | 0.7.0 (18.12.2017) | |
288 | ------------------ | |
289 | ||
290 | * Changes the way request contexts are managed. Let's Flask be responsible | |
291 | for the context, which fixes some subtle bugs. | |
292 | ||
293 | 0.6.2 (26.02.2017) | |
294 | ------------------ | |
295 | ||
296 | * Add support for OS chosen port in ``LiveServerTestCase`` | |
297 | * Better error messages when missing required modules | |
298 | * ``assertRedirects`` now supports all valid redirect codes as specified | |
299 | in the HTTP protocol | |
300 | * Fixed bug that caused ``TypeError`` instead of ``AssertionError`` when | |
301 | testing against used templates | |
302 | * Fixed bug in ``assertRedirects`` where the location was not being | |
303 | checked properly | |
304 | ||
305 | 0.6.1 (03.09.2016) | |
306 | ------------------ | |
307 | ||
308 | * Fix issues that prevented tests from running when blinker was not installed | |
309 | ||
310 | 0.6.0 (02.09.2016) | |
311 | ------------------ | |
312 | ||
313 | * ``LiveServerTestCase`` will now start running as soon as the server is up | |
314 | * ``assertRedirects`` now respects the ``SERVER_NAME`` config value and can compare against absolute URLs | |
315 | * Compatibility with Flask 0.11.1 | |
316 | ||
317 | 0.5.0 (12.06.2016) | |
318 | ------------------ | |
319 | ||
320 | * Improvements to ``LiveServerTestCase`` | |
321 | ||
322 | * The test case will now block until the server is available | |
323 | * Fixed an issue where no request context was available | |
324 | * Fixed an issue where tests would be run twice when ``DEBUG`` was set to True | |
325 | ||
326 | * Add missing message arguments for assertRedirects and assertContext | |
327 | * Better default failure message for assertRedirects | |
328 | * Better default failure message for assertTemplateUsed | |
329 | * Fix an issue that caused the ``render_templates`` option to not clean up after itself if set to False | |
330 | * Update docs to use new Flask extension import specification | |
242 | 331 | |
243 | 332 | 0.4.2 (24.07.2014) |
244 | 333 | ------------------ |
268 | 357 | API |
269 | 358 | === |
270 | 359 | |
271 | .. module:: flask.ext.testing | |
360 | .. module:: flask_testing | |
272 | 361 | |
273 | 362 | .. autoclass:: TestCase |
274 | 363 | :members: |
10 | 10 | from __future__ import absolute_import, with_statement |
11 | 11 | |
12 | 12 | import gc |
13 | import multiprocessing | |
14 | import socket | |
13 | 15 | import time |
16 | ||
17 | try: | |
18 | import socketserver | |
19 | except ImportError: | |
20 | # Python 2 SocketServer fallback | |
21 | import SocketServer as socketserver | |
22 | ||
14 | 23 | try: |
15 | 24 | import unittest2 as unittest |
16 | 25 | except ImportError: |
17 | 26 | import unittest |
18 | import multiprocessing | |
19 | ||
20 | from werkzeug import cached_property | |
27 | ||
28 | try: | |
29 | from urllib.parse import urlparse, urljoin | |
30 | except ImportError: | |
31 | # Python 2 urlparse fallback | |
32 | from urlparse import urlparse, urljoin | |
33 | ||
34 | from werkzeug.utils import cached_property | |
21 | 35 | |
22 | 36 | # Use Flask's preferred JSON module so that our runtime behavior matches. |
23 | 37 | from flask import json_available, templating, template_rendered |
38 | ||
39 | try: | |
40 | from flask import message_flashed | |
41 | ||
42 | _is_message_flashed = True | |
43 | except ImportError: | |
44 | message_flashed = None | |
45 | _is_message_flashed = False | |
46 | ||
24 | 47 | if json_available: |
25 | 48 | from flask import json |
26 | 49 | |
28 | 51 | # available in this version of Flask |
29 | 52 | try: |
30 | 53 | import blinker |
54 | ||
31 | 55 | _is_signals = True |
32 | 56 | except ImportError: # pragma: no cover |
33 | 57 | _is_signals = False |
43 | 67 | """ |
44 | 68 | Mixin with testing helper methods |
45 | 69 | """ |
70 | ||
46 | 71 | @cached_property |
47 | 72 | def json(self): |
48 | 73 | if not json_available: # pragma: no cover |
68 | 93 | return "" |
69 | 94 | |
70 | 95 | |
96 | def _check_for_message_flashed_support(): | |
97 | if not _is_signals or not _is_message_flashed: | |
98 | raise RuntimeError( | |
99 | "Your version of Flask doesn't support message_flashed. " | |
100 | "This requires Flask 0.10+ with the blinker module installed." | |
101 | ) | |
102 | ||
103 | ||
104 | def _check_for_signals_support(): | |
105 | if not _is_signals: | |
106 | raise RuntimeError( | |
107 | "Your version of Flask doesn't support signals. " | |
108 | "This requires Flask 0.6+ with the blinker module installed." | |
109 | ) | |
110 | ||
111 | ||
71 | 112 | class TestCase(unittest.TestCase): |
72 | ||
73 | 113 | render_templates = True |
74 | 114 | run_gc_after_test = False |
75 | 115 | |
92 | 132 | finally: |
93 | 133 | self._post_teardown() |
94 | 134 | |
135 | def debug(self): | |
136 | try: | |
137 | self._pre_setup() | |
138 | super(TestCase, self).debug() | |
139 | finally: | |
140 | self._post_teardown() | |
141 | ||
95 | 142 | def _pre_setup(self): |
96 | 143 | self.app = self.create_app() |
97 | 144 | |
109 | 156 | templating._render = _empty_render |
110 | 157 | |
111 | 158 | self.templates = [] |
159 | self.flashed_messages = [] | |
160 | ||
112 | 161 | if _is_signals: |
113 | 162 | template_rendered.connect(self._add_template) |
163 | ||
164 | if _is_message_flashed: | |
165 | message_flashed.connect(self._add_flash_message) | |
166 | ||
167 | def _add_flash_message(self, app, message, category): | |
168 | self.flashed_messages.append((message, category)) | |
114 | 169 | |
115 | 170 | def _add_template(self, app, template, context): |
116 | 171 | if len(self.templates) > 0: |
133 | 188 | if hasattr(self, 'templates'): |
134 | 189 | del self.templates |
135 | 190 | |
191 | if hasattr(self, 'flashed_messages'): | |
192 | del self.flashed_messages | |
193 | ||
136 | 194 | if _is_signals: |
137 | 195 | template_rendered.disconnect(self._add_template) |
138 | if hasattr(self, '_true_render'): | |
139 | templating._render = self._true_render | |
196 | ||
197 | if _is_message_flashed: | |
198 | message_flashed.disconnect(self._add_flash_message) | |
199 | ||
200 | if hasattr(self, '_original_template_render'): | |
201 | templating._render = self._original_template_render | |
140 | 202 | |
141 | 203 | if self.run_gc_after_test: |
142 | 204 | gc.collect() |
205 | ||
206 | def assertMessageFlashed(self, message, category='message'): | |
207 | """ | |
208 | Checks if a given message was flashed. | |
209 | Only works if your version of Flask has message_flashed | |
210 | signal support (0.10+) and blinker is installed. | |
211 | ||
212 | :param message: expected message | |
213 | :param category: expected message category | |
214 | """ | |
215 | _check_for_message_flashed_support() | |
216 | ||
217 | for _message, _category in self.flashed_messages: | |
218 | if _message == message and _category == category: | |
219 | return True | |
220 | ||
221 | raise AssertionError("Message '%s' in category '%s' wasn't flashed" % (message, category)) | |
222 | ||
223 | assert_message_flashed = assertMessageFlashed | |
143 | 224 | |
144 | 225 | def assertTemplateUsed(self, name, tmpl_name_attribute='name'): |
145 | 226 | """ |
154 | 235 | :param name: template name |
155 | 236 | :param tmpl_name_attribute: template engine specific attribute name |
156 | 237 | """ |
157 | if not _is_signals: | |
158 | raise RuntimeError("Signals not supported") | |
238 | _check_for_signals_support() | |
239 | ||
240 | used_templates = [] | |
159 | 241 | |
160 | 242 | for template, context in self.templates: |
161 | 243 | if getattr(template, tmpl_name_attribute) == name: |
162 | 244 | return True |
163 | raise AssertionError("template %s not used" % name) | |
245 | ||
246 | used_templates.append(template) | |
247 | ||
248 | raise AssertionError("Template %s not used. Templates were used: %s" % (name, ' '.join(repr(used_templates)))) | |
164 | 249 | |
165 | 250 | assert_template_used = assertTemplateUsed |
166 | 251 | |
176 | 261 | :versionadded: 0.2 |
177 | 262 | :param name: name of variable |
178 | 263 | """ |
179 | if not _is_signals: | |
180 | raise RuntimeError("Signals not supported") | |
264 | _check_for_signals_support() | |
181 | 265 | |
182 | 266 | for template, context in self.templates: |
183 | 267 | if name in context: |
184 | 268 | return context[name] |
185 | 269 | raise ContextVariableDoesNotExist |
186 | 270 | |
187 | def assertContext(self, name, value): | |
271 | def assertContext(self, name, value, message=None): | |
188 | 272 | """ |
189 | 273 | Checks if given name exists in the template context |
190 | 274 | and equals the given value. |
195 | 279 | """ |
196 | 280 | |
197 | 281 | try: |
198 | self.assertEqual(self.get_context_variable(name), value) | |
282 | self.assertEqual(self.get_context_variable(name), value, message) | |
199 | 283 | except ContextVariableDoesNotExist: |
200 | self.fail("Context variable does not exist: %s" % name) | |
284 | self.fail(message or "Context variable does not exist: %s" % name) | |
201 | 285 | |
202 | 286 | assert_context = assertContext |
203 | 287 | |
204 | def assertRedirects(self, response, location): | |
288 | def assertRedirects(self, response, location, message=None): | |
205 | 289 | """ |
206 | 290 | Checks if response is an HTTP redirect to the |
207 | 291 | given location. |
208 | 292 | |
209 | 293 | :param response: Flask response |
210 | :param location: relative URL (i.e. without **http://localhost**) | |
211 | """ | |
212 | self.assertTrue(response.status_code in (301, 302)) | |
213 | self.assertEqual(response.location, "http://localhost" + location) | |
294 | :param location: relative URL path to SERVER_NAME or an absolute URL | |
295 | """ | |
296 | parts = urlparse(location) | |
297 | ||
298 | if parts.netloc: | |
299 | expected_location = location | |
300 | else: | |
301 | server_name = self.app.config.get('SERVER_NAME') or 'localhost' | |
302 | expected_location = urljoin("http://%s" % server_name, location) | |
303 | ||
304 | valid_status_codes = (301, 302, 303, 305, 307) | |
305 | valid_status_code_str = ', '.join(str(code) for code in valid_status_codes) | |
306 | not_redirect = "HTTP Status %s expected but got %d" % (valid_status_code_str, response.status_code) | |
307 | self.assertTrue(response.status_code in valid_status_codes, message or not_redirect) | |
308 | self.assertEqual(response.location, expected_location, message) | |
214 | 309 | |
215 | 310 | assert_redirects = assertRedirects |
216 | 311 | |
323 | 418 | # Inspired by https://docs.djangoproject.com/en/dev/topics/testing/#django.test.LiveServerTestCase |
324 | 419 | |
325 | 420 | class LiveServerTestCase(unittest.TestCase): |
326 | ||
327 | 421 | def create_app(self): |
328 | 422 | """ |
329 | 423 | Create your Flask app here, with any |
339 | 433 | |
340 | 434 | # Get the app |
341 | 435 | self.app = self.create_app() |
436 | ||
437 | self._configured_port = self.app.config.get('LIVESERVER_PORT', 5000) | |
438 | self._port_value = multiprocessing.Value('i', self._configured_port) | |
439 | ||
440 | # We need to create a context in order for extensions to catch up | |
441 | self._ctx = self.app.test_request_context() | |
442 | self._ctx.push() | |
342 | 443 | |
343 | 444 | try: |
344 | 445 | self._spawn_live_server() |
345 | 446 | super(LiveServerTestCase, self).__call__(result) |
346 | 447 | finally: |
448 | self._post_teardown() | |
347 | 449 | self._terminate_live_server() |
348 | 450 | |
349 | 451 | def get_server_url(self): |
350 | 452 | """ |
351 | 453 | Return the url of the test server |
352 | 454 | """ |
353 | return 'http://localhost:%s' % self.port | |
455 | return 'http://localhost:%s' % self._port_value.value | |
354 | 456 | |
355 | 457 | def _spawn_live_server(self): |
356 | 458 | self._process = None |
357 | self.port = self.app.config.get('LIVESERVER_PORT', 5000) | |
358 | ||
359 | worker = lambda app, port: app.run(port=port) | |
459 | port_value = self._port_value | |
460 | ||
461 | def worker(app, port): | |
462 | # Based on solution: http://stackoverflow.com/a/27598916 | |
463 | # Monkey-patch the server_bind so we can determine the port bound by Flask. | |
464 | # This handles the case where the port specified is `0`, which means that | |
465 | # the OS chooses the port. This is the only known way (currently) of getting | |
466 | # the port out of Flask once we call `run`. | |
467 | original_socket_bind = socketserver.TCPServer.server_bind | |
468 | def socket_bind_wrapper(self): | |
469 | ret = original_socket_bind(self) | |
470 | ||
471 | # Get the port and save it into the port_value, so the parent process | |
472 | # can read it. | |
473 | (_, port) = self.socket.getsockname() | |
474 | port_value.value = port | |
475 | socketserver.TCPServer.server_bind = original_socket_bind | |
476 | return ret | |
477 | ||
478 | socketserver.TCPServer.server_bind = socket_bind_wrapper | |
479 | app.run(port=port, use_reloader=False) | |
360 | 480 | |
361 | 481 | self._process = multiprocessing.Process( |
362 | target=worker, args=(self.app, self.port) | |
482 | target=worker, args=(self.app, self._configured_port) | |
363 | 483 | ) |
364 | 484 | |
365 | 485 | self._process.start() |
366 | 486 | |
367 | # we must wait the server start listening | |
368 | time.sleep(1) | |
487 | # We must wait for the server to start listening, but give up | |
488 | # after a specified maximum timeout | |
489 | timeout = self.app.config.get('LIVESERVER_TIMEOUT', 5) | |
490 | start_time = time.time() | |
491 | ||
492 | while True: | |
493 | elapsed_time = (time.time() - start_time) | |
494 | if elapsed_time > timeout: | |
495 | raise RuntimeError( | |
496 | "Failed to start the server after %d seconds. " % timeout | |
497 | ) | |
498 | ||
499 | if self._can_ping_server(): | |
500 | break | |
501 | ||
502 | def _can_ping_server(self): | |
503 | host, port = self._get_server_address() | |
504 | if port == 0: | |
505 | # Port specified by the user was 0, and the OS has not yet assigned | |
506 | # the proper port. | |
507 | return False | |
508 | ||
509 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
510 | try: | |
511 | sock.connect((host, port)) | |
512 | except socket.error as e: | |
513 | success = False | |
514 | else: | |
515 | success = True | |
516 | finally: | |
517 | sock.close() | |
518 | ||
519 | return success | |
520 | ||
521 | def _get_server_address(self): | |
522 | """ | |
523 | Gets the server address used to test the connection with a socket. | |
524 | Respects both the LIVESERVER_PORT config value and overriding | |
525 | get_server_url() | |
526 | """ | |
527 | parts = urlparse(self.get_server_url()) | |
528 | ||
529 | host = parts.hostname | |
530 | port = parts.port | |
531 | ||
532 | if port is None: | |
533 | if parts.scheme == 'http': | |
534 | port = 80 | |
535 | elif parts.scheme == 'https': | |
536 | port = 443 | |
537 | else: | |
538 | raise RuntimeError( | |
539 | "Unsupported server url scheme: %s" % parts.scheme | |
540 | ) | |
541 | ||
542 | return host, port | |
543 | ||
544 | def _post_teardown(self): | |
545 | if getattr(self, '_ctx', None) is not None: | |
546 | self._ctx.pop() | |
547 | del self._ctx | |
369 | 548 | |
370 | 549 | def _terminate_live_server(self): |
371 | 550 | if self._process: |
22 | 22 | ] |
23 | 23 | |
24 | 24 | if sys.version_info[0] < 3: |
25 | tests_require.append('twill==0.9') | |
25 | tests_require.append('twill==0.9.1') | |
26 | 26 | |
27 | 27 | if sys.version_info < (2, 6): |
28 | 28 | tests_require.append('simplejson') |
30 | 30 | |
31 | 31 | setup( |
32 | 32 | name='Flask-Testing', |
33 | version='0.4.2', | |
33 | version='0.8.0', | |
34 | 34 | url='https://github.com/jarus/flask-testing', |
35 | 35 | license='BSD', |
36 | 36 | author='Dan Jacob', |
1 | 1 | |
2 | 2 | from flask_testing import is_twill_available |
3 | 3 | |
4 | from .test_utils import TestSetup, TestSetupFailure, TestClientUtils, TestLiveServer, TestTeardownGraceful | |
5 | 4 | from .test_twill import TestTwill, TestTwillDeprecated |
5 | from .test_utils import TestSetup, TestSetupFailure, TestClientUtils, \ | |
6 | TestLiveServer, TestTeardownGraceful, TestRenderTemplates, \ | |
7 | TestNotRenderTemplates, TestRestoreTheRealRender, \ | |
8 | TestLiveServerOSPicksPort | |
6 | 9 | |
7 | 10 | |
8 | 11 | def suite(): |
9 | 12 | suite = unittest.TestSuite() |
10 | 13 | suite.addTest(unittest.makeSuite(TestSetup)) |
11 | 14 | suite.addTest(unittest.makeSuite(TestSetupFailure)) |
12 | suite.addTest(unittest.makeSuite(TestTeardownGraceful)) | |
13 | 15 | suite.addTest(unittest.makeSuite(TestClientUtils)) |
14 | 16 | suite.addTest(unittest.makeSuite(TestLiveServer)) |
17 | suite.addTest(unittest.makeSuite(TestLiveServerOSPicksPort)) | |
18 | suite.addTest(unittest.makeSuite(TestTeardownGraceful)) | |
19 | suite.addTest(unittest.makeSuite(TestRenderTemplates)) | |
20 | suite.addTest(unittest.makeSuite(TestNotRenderTemplates)) | |
21 | suite.addTest(unittest.makeSuite(TestRestoreTheRealRender)) | |
15 | 22 | if is_twill_available: |
16 | 23 | suite.addTest(unittest.makeSuite(TestTwill)) |
17 | 24 | suite.addTest(unittest.makeSuite(TestTwillDeprecated)) |
0 | from flask import Flask, Response, abort, redirect, jsonify, render_template,\ | |
1 | url_for | |
0 | from flask import ( | |
1 | Flask, | |
2 | Response, | |
3 | abort, | |
4 | redirect, | |
5 | jsonify, | |
6 | render_template, | |
7 | url_for, | |
8 | flash, | |
9 | request | |
10 | ) | |
2 | 11 | |
3 | 12 | |
4 | 13 | def create_app(): |
5 | 14 | |
6 | 15 | app = Flask(__name__) |
16 | app.config['SECRET_KEY'] = 'super secret testing key' | |
7 | 17 | |
8 | 18 | @app.route("/") |
9 | 19 | def index(): |
13 | 23 | def index_with_template(): |
14 | 24 | return render_template("index.html", name="test") |
15 | 25 | |
26 | @app.route("/flash/") | |
27 | def index_with_flash(): | |
28 | flash("Flashed message") | |
29 | return render_template("index.html") | |
30 | ||
31 | @app.route("/no_flash/") | |
32 | def index_without_flash(): | |
33 | return render_template("index.html") | |
34 | ||
16 | 35 | @app.route("/oops/") |
17 | 36 | def bad_url(): |
18 | 37 | abort(404) |
19 | 38 | |
20 | 39 | @app.route("/redirect/") |
21 | 40 | def redirect_to_index(): |
22 | return redirect(url_for("index")) | |
41 | code = request.args.get('code') or 301 | |
42 | return redirect(url_for("index"), code=code) | |
43 | ||
44 | @app.route("/external_redirect/") | |
45 | def redirect_to_flask_docs(): | |
46 | return redirect("http://flask.pocoo.org/") | |
23 | 47 | |
24 | 48 | @app.route("/ajax/") |
25 | 49 | def ajax(): |
26 | return jsonify(name="test") | |
50 | return jsonify(**dict(name="test")) | |
27 | 51 | |
28 | 52 | @app.route("/forbidden/") |
29 | 53 | def forbidden(): |
55 | 55 | try: |
56 | 56 | self.assertStatus(self.client.get('/'), 404, expected_message) |
57 | 57 | except AssertionError as e: |
58 | self.assertTrue(expected_message in e.args[0] or \ | |
59 | expected_message in e.message) | |
58 | self.assertTrue(expected_message in str(e)) | |
60 | 59 | |
61 | 60 | def test_default_status_failure_message(self): |
62 | 61 | expected_message = 'HTTP Status 404 expected but got 200' |
63 | 62 | try: |
64 | 63 | self.assertStatus(self.client.get('/'), 404) |
65 | 64 | except AssertionError as e: |
66 | self.assertTrue(expected_message in e.args[0] or \ | |
67 | expected_message in e.message) | |
65 | self.assertTrue(expected_message in str(e)) | |
68 | 66 | |
69 | 67 | def test_assert_200(self): |
70 | 68 | self.assert200(self.client.get("/")) |
88 | 86 | response = self.client.get("/redirect/") |
89 | 87 | self.assertRedirects(response, "/") |
90 | 88 | |
89 | def test_assert_redirects_full_url(self): | |
90 | response = self.client.get("/external_redirect/") | |
91 | self.assertRedirects(response, "http://flask.pocoo.org/") | |
92 | ||
93 | def test_assert_redirects_failure_message(self): | |
94 | response = self.client.get("/") | |
95 | try: | |
96 | self.assertRedirects(response, "/anything") | |
97 | except AssertionError as e: | |
98 | self.assertTrue("HTTP Status 301, 302, 303, 305, 307 expected but got 200" in str(e)) | |
99 | ||
100 | def test_assert_redirects_custom_message(self): | |
101 | response = self.client.get("/") | |
102 | try: | |
103 | self.assertRedirects(response, "/anything", "Custom message") | |
104 | except AssertionError as e: | |
105 | self.assertTrue("Custom message" in str(e)) | |
106 | ||
107 | def test_assert_redirects_valid_status_codes(self): | |
108 | valid_redirect_status_codes = (301, 302, 303, 305, 307) | |
109 | ||
110 | for status_code in valid_redirect_status_codes: | |
111 | response = self.client.get("/redirect/?code=" + str(status_code)) | |
112 | self.assertRedirects(response, "/") | |
113 | self.assertStatus(response, status_code) | |
114 | ||
115 | def test_assert_redirects_invalid_status_code(self): | |
116 | status_code = 200 | |
117 | response = self.client.get("/redirect/?code=" + str(status_code)) | |
118 | self.assertStatus(response, status_code) | |
119 | try: | |
120 | self.assertRedirects(response, "/") | |
121 | except AssertionError as e: | |
122 | self.assertTrue("HTTP Status 301, 302, 303, 305, 307 expected but got 200" in str(e)) | |
123 | ||
91 | 124 | def test_assert_template_used(self): |
92 | 125 | try: |
93 | 126 | self.client.get("/template/") |
96 | 129 | pass |
97 | 130 | |
98 | 131 | def test_assert_template_not_used(self): |
99 | self.client.get("/") | |
100 | try: | |
101 | self.assert_template_used("index.html") | |
102 | assert False | |
103 | except AssertionError: | |
104 | pass | |
132 | self.client.get("/template/") | |
133 | try: | |
134 | self.assertRaises(AssertionError, self.assert_template_used, "invalid.html") | |
105 | 135 | except RuntimeError: |
106 | 136 | pass |
107 | 137 | |
116 | 146 | try: |
117 | 147 | self.client.get("/template/") |
118 | 148 | self.assert_context("name", "test") |
149 | except RuntimeError: | |
150 | pass | |
151 | ||
152 | def test_assert_context_custom_message(self): | |
153 | self.client.get("/template/") | |
154 | try: | |
155 | self.assert_context("name", "nothing", "Custom message") | |
156 | except AssertionError as e: | |
157 | self.assertTrue("Custom message" in str(e)) | |
119 | 158 | except RuntimeError: |
120 | 159 | pass |
121 | 160 | |
129 | 168 | except RuntimeError: |
130 | 169 | pass |
131 | 170 | |
171 | def test_assert_bad_context_custom_message(self): | |
172 | self.client.get("/template/") | |
173 | try: | |
174 | self.assert_context("foo", "foo", "Custom message") | |
175 | except AssertionError as e: | |
176 | self.assertTrue("Custom message" in str(e)) | |
177 | except RuntimeError: | |
178 | pass | |
179 | ||
132 | 180 | def test_assert_get_context_variable_not_exists(self): |
133 | 181 | try: |
134 | 182 | self.client.get("/template/") |
137 | 185 | except RuntimeError: |
138 | 186 | pass |
139 | 187 | |
140 | ||
141 | class TestLiveServer(LiveServerTestCase): | |
142 | ||
143 | def create_app(self): | |
144 | app = create_app() | |
145 | app.config['LIVESERVER_PORT'] = 8943 | |
146 | return app | |
147 | ||
148 | def test_server_process_is_spawned(self): | |
149 | process = self._process | |
150 | ||
151 | # Check the process is spawned | |
152 | self.assertNotEqual(process, None) | |
153 | ||
154 | # Check the process is alive | |
155 | self.assertTrue(process.is_alive()) | |
156 | ||
157 | def test_server_listening(self): | |
158 | response = urlopen(self.get_server_url()) | |
159 | self.assertTrue(b'OK' in response.read()) | |
160 | self.assertEqual(response.code, 200) | |
188 | def test_assert_flashed_messages_succeed(self): | |
189 | try: | |
190 | self.client.get("/flash/") | |
191 | self.assertMessageFlashed("Flashed message") | |
192 | except RuntimeError: | |
193 | pass | |
194 | ||
195 | def test_assert_flashed_messages_failed(self): | |
196 | try: | |
197 | self.client.get("/flash/") | |
198 | self.assertRaises(AssertionError, self.assertMessageFlashed, "Flask-testing has assertMessageFlashed now") | |
199 | except RuntimeError: | |
200 | pass | |
201 | ||
202 | def test_assert_no_flashed_messages_fail(self): | |
203 | try: | |
204 | self.client.get("/no_flash/") | |
205 | self.assertRaises(AssertionError, self.assertMessageFlashed, "Flashed message") | |
206 | except RuntimeError: | |
207 | pass | |
208 | ||
209 | ||
210 | class BaseTestLiveServer(LiveServerTestCase): | |
211 | ||
212 | def test_server_process_is_spawned(self): | |
213 | process = self._process | |
214 | ||
215 | # Check the process is spawned | |
216 | self.assertNotEqual(process, None) | |
217 | ||
218 | # Check the process is alive | |
219 | self.assertTrue(process.is_alive()) | |
220 | ||
221 | def test_server_listening(self): | |
222 | response = urlopen(self.get_server_url()) | |
223 | self.assertTrue(b'OK' in response.read()) | |
224 | self.assertEqual(response.code, 200) | |
225 | ||
226 | ||
227 | class TestLiveServer(BaseTestLiveServer): | |
228 | ||
229 | def create_app(self): | |
230 | app = create_app() | |
231 | app.config['LIVESERVER_PORT'] = 8943 | |
232 | return app | |
233 | ||
234 | ||
235 | class TestLiveServerOSPicksPort(BaseTestLiveServer): | |
236 | ||
237 | def create_app(self): | |
238 | app = create_app() | |
239 | app.config['LIVESERVER_PORT'] = 0 | |
240 | return app | |
161 | 241 | |
162 | 242 | |
163 | 243 | class TestNotRenderTemplates(TestCase): |
170 | 250 | def test_assert_not_process_the_template(self): |
171 | 251 | response = self.client.get("/template/") |
172 | 252 | |
173 | assert "" == response.data | |
253 | assert len(response.data) == 0 | |
174 | 254 | |
175 | 255 | def test_assert_template_rendered_signal_sent(self): |
176 | 256 | self.client.get("/template/") |
188 | 268 | def test_assert_not_process_the_template(self): |
189 | 269 | response = self.client.get("/template/") |
190 | 270 | |
191 | assert "" != response.data | |
271 | assert len(response.data) > 0 | |
192 | 272 | |
193 | 273 | |
194 | 274 | class TestRestoreTheRealRender(TestCase): |
205 | 285 | |
206 | 286 | response = self.client.get("/template/") |
207 | 287 | |
208 | assert "" != response.data | |
288 | assert len(response.data) > 0 |