summaryrefslogtreecommitdiff
path: root/docs/testing-applications.txt
diff options
context:
space:
mode:
Diffstat (limited to 'docs/testing-applications.txt')
-rw-r--r--docs/testing-applications.txt156
1 files changed, 156 insertions, 0 deletions
diff --git a/docs/testing-applications.txt b/docs/testing-applications.txt
new file mode 100644
index 0000000..76ca495
--- /dev/null
+++ b/docs/testing-applications.txt
@@ -0,0 +1,156 @@
+Testing Applications with Paste
++++++++++++++++++++++++++++++++
+
+:author: Ian Bicking <ianb@colorstudy.com>
+:revision: $Rev$
+:date: $LastChangedDate$
+
+.. contents::
+
+Introduction
+============
+
+Paste includes functionality for testing your application in a
+convenient manner. These facilities are quite young, and feedback is
+invited. Feedback and discussion should take place on the
+`Paste-users list
+<http://groups.google.com/group/paste-users>`_.
+
+These facilities let you test your Paste and WSGI-based applications
+easily and without a server.
+
+.. include:: include/contact.txt
+
+The Tests Themselves
+====================
+
+The ``app`` object is a wrapper around your application, with many
+methods to make testing convenient. Here's an example test script::
+
+ def test_myapp():
+ res = app.get('/view', params={'id': 10})
+ # We just got /view?id=10
+ res.mustcontain('Item 10')
+ res = app.post('/view', params={'id': 10, 'name': 'New item
+ name'})
+ # The app does POST-and-redirect...
+ res = res.follow()
+ assert res.request.url == '/view?id=10'
+ res.mustcontain('New item name')
+ res.mustcontain('Item updated')
+
+The methods of the ``app`` object (a ``paste.tests.fixture.TestApp``
+object):
+
+``get(url, params={}, headers={}, status=None)``:
+ Gets the URL. URLs are based in the root of your application; no
+ domains are allowed. Parameters can be given as a dictionary, or
+ included directly in the ``url``. Headers can also be added.
+
+ This tests that the status is a ``200 OK`` or a redirect header,
+ unless you pass in a ``status``. A status of ``"*"`` will never
+ fail; or you can assert a specific status (like ``500``).
+
+ Also, if any errors are written to the error stream this will
+ raise an error.
+
+``post(url, params={}, headers={}, status=None, upload_files=())``:
+ POSTS to the URL. Like GET, except also allows for uploading
+ files. The uploaded files are a list of ``(field_name, filename,
+ file_content)``.
+
+ If you don't want to do a urlencoded post body, you can put a
+ ``content-type`` header in your header, and pass the body in as a
+ string with ``params``.
+
+The response object:
+
+``header(header_name, [default])``:
+ Returns the named header. It's an error if there is more than one
+ matching header. If you don't provide a default, it is an error
+ if there is no matching header.
+
+``all_headers(header_name):``
+ Returns a list of all matching headers.
+
+``follow(**kw)``:
+ Follows the redirect, returning the new response. It is an error
+ if this response wasn't a redirect. Any keyword arguments are
+ passed to ``app.get`` (e.g., ``status``).
+
+``x in res``:
+ Returns True if the string is found in the response. Whitespace
+ is normalized for this test.
+
+``mustcontain(*strings)``:
+ Raises an error if any of the strings are not found in the
+ response.
+
+``showbrowser()``:
+ Opens the HTML response in a browser; useful for debugging.
+
+``str(res)``:
+ Gives a slightly-compacted version of the response.
+
+``click(description=None, linkid=None, href=None, anchor=None, index=None, verbose=False)``:
+ Clicks the described link (`see docstring for more
+ <./class-paste.fixture.TestResponse.html#click>`_)
+
+``forms``:
+ Return a dictionary of forms; you can use both indexes (refer to
+ the forms in order) or the string ids of forms (if you've given
+ them ids) to identify the form. See `Form Submissions <#form-submissions>`_ for
+ more on the form objects.
+
+Request objects:
+
+``url``:
+ The url requested.
+
+``environ``:
+ The environment used for the request.
+
+``full_url``:
+ The url with query string.
+
+Form Submissions
+================
+
+You can fill out and submit forms from your tests. First you get the
+form::
+
+ res = testapp.get('/entry_form')
+ form = res.forms[0]
+
+Then you fill it in fields::
+
+ # when there's one unambiguous name field:
+ form['name'] = 'Bob'
+ # Enter something into the first field named 'age'
+ form.set('age', '45', index=1)
+
+Finally you submit::
+
+ # Submit with no particular submit button pressed:
+ form.submit()
+ # Or submit a button:
+ form.submit('submit_button_name')
+
+Framework Hooks
+===============
+
+Frameworks can detect that they are in a testing environment by the
+presence (and truth) of the WSGI environmental variable
+``"paste.testing"``.
+
+More generally, frameworks can detect that something (possibly a test
+fixture) is ready to catch unexpected errors by the presence and truth
+of ``"paste.throw_errors"`` (this is sometimes set outside of testing
+fixtures too, when an error-handling middleware is in place).
+
+Frameworks that want to expose the inner structure of the request may
+use ``"paste.testing_variables"``. This will be a dictionary -- any
+values put into that dictionary will become attributes of the response
+object. So if you do ``env["paste.testing_variables"]['template'] =
+template_name`` in your framework, then ``response.template`` will be
+``template_name``.