# TestApp

## Making Requests

To make a request, use:

    app.get('/path', [params], [headers], [extra_environ], ...)

This call to `get()` does a request for `/path`, with any params, extra headers or WSGI environment keys that you indicate. This returns a `TestResponse` object, based on `webob.response.Response`. It has some additional methods to make it easier to test.

If you want to do a POST request, use:

    app.post('/path', {'vars': 'values'}, [headers], [extra_environ],
             [upload_files], ...)

Specifically the second argument of `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 `put()` and `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 `webtest.app.TestApp.post_json()`:

    >>> 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 `webtest.app.TestApp.get()` and using `json`:

To just parse body of the response, use Response.json:

    >>> 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:

    app.get('/secret', extra_environ=dict(REMOTE_USER='bob'))

If you want all your requests to have this key, do:

    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 dictionary:

    app = TestApp(my_app)
    app.authorization = ('Basic', ('user', 'password'))

You can also use bearer token or JWT authorization types:

    app = TestApp(my_app)
    app.authorization = ('Bearer', 'mytoken')
    # or
    app.authorization = ('JWT', 'myjwt')

## 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 `python:wsgiref.validate` (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`.