1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
TestApp
=======
Making Requests
---------------
To make a request, use:
.. code-block:: python
app.get('/path', [params], [headers], [extra_environ], ...)
This call to :meth:`~webtest.TestApp.get` does a request for
``/path``, with any params, extra headers or WSGI
environment keys that you indicate. This returns a
:class:`~webtest.TestResponse` object,
based on :class:`webob.response.Response`. It has some
additional methods to make it easier to test.
If you want to do a POST request, use:
.. code-block:: python
app.post('/path', {'vars': 'values'}, [headers], [extra_environ],
[upload_files], ...)
Specifically the second argument of :meth:`~webtest.TestApp.post`
is the *body* of the request. You
can pass in a dictionary (or dictionary-like object), or a string
body (dictionary objects are turned into HTML form submissions).
You can also pass in the keyword argument upload_files, which is a
list of ``[(fieldname, filename, field_content)]``. File uploads use a
different form submission data type to pass the structured data.
You can use :meth:`~webtest.TestApp.put` and
:meth:`~webtest.TestApp.delete` for PUT and DELETE requests.
Making JSON Requests
--------------------
Webtest provide some facilities to test json apis.
The ``*_json`` methods will transform data to json before ``POST``/``PUT`` and
add the correct ``Content-Type`` for you.
Also Response have an attribute ``.json`` to allow you to retrieve json
contents as a python dict.
Doing *POST* request with :meth:`webtest.TestApp.post_json`:
.. code-block:: python
>>> resp = app.post_json('/resource/', dict(id=1, value='value'))
>>> print(resp.request)
POST /resource/ HTTP/1.0
Content-Length: 27
Content-Type: application/json
...
>>> resp.json == {'id': 1, 'value': 'value'}
True
Doing *GET* request with :meth:`webtest.TestApp.get` and using :attr:`webtest.response.json`:
To just parse body of the response, use Response.json:
.. code-block:: python
>>> resp = app.get('/resource/1/')
>>> print(resp.request)
GET /resource/1/ HTTP/1.0
...
>>> resp.json == {'id': 1, 'value': 'value'}
True
Modifying the Environment & Simulating Authentication
------------------------------------------------------
The best way to simulate authentication is if your application looks
in ``environ['REMOTE_USER']`` to see if someone is authenticated.
Then you can simply set that value, like:
.. code-block:: python
app.get('/secret', extra_environ=dict(REMOTE_USER='bob'))
If you want *all* your requests to have this key, do:
.. code-block:: python
app = TestApp(my_app, extra_environ=dict(REMOTE_USER='bob'))
If you have to use HTTP authorization you can use the ``.authorization``
property to set the ``HTTP_AUTHORIZATION`` key of the extra_environ
dictionnary:
.. code-block:: python
app = TestApp(my_app)
app.authorization = ('Basic', ('user', 'password'))
Only Basic auth is supported for now.
Testing a non wsgi application
------------------------------
You can use WebTest to test an application on a real web server.
Just pass an url to the `TestApp` instead of a WSGI application::
app = TestApp('http://my.cool.websi.te')
You can also use the ``WEBTEST_TARGET_URL`` env var to switch from a WSGI
application to a real server without having to modify your code::
os.environ['WEBTEST_TARGET_URL'] = 'http://my.cool.websi.te'
app = TestApp(wsgiapp) # will use the WEBTEST_TARGET_URL instead of the wsgiapp
By default the proxy will use ``httplib`` but you can use other backends by
adding an anchor to your url::
app = TestApp('http://my.cool.websi.te#urllib3')
app = TestApp('http://my.cool.websi.te#requests')
app = TestApp('http://my.cool.websi.te#restkit')
What Is Tested By Default
--------------------------
A key concept behind WebTest is that there's lots of things you
shouldn't have to check everytime you do a request. It is assumed
that the response will either be a 2xx or 3xx response; if it isn't an
exception will be raised (you can override this for a request, of
course). The WSGI application is tested for WSGI compliance with
a slightly modified version of `wsgiref.validate
<http://python.org/doc/current/lib/module-wsgiref.validate.html>`_
(modified to support arguments to ``InputWrapper.readline``)
automatically. Also it checks that nothing is printed to the
``environ['wsgi.errors']`` error stream, which typically indicates a
problem (one that would be non-fatal in a production situation, but if
you are testing is something you should avoid).
To indicate another status is expected, use the keyword argument
``status=404`` to (for example) check that it is a 404 status, or
``status="*"`` to allow any status, or ``status="400 Custom Bad Request"``
to use custom reason phrase.
If you expect errors to be printed, use ``expect_errors=True``.
|