# Testing Applications with WebTest

author:

  Ian Bicking <ianb@colorstudy.com>

maintainer:

  Gael Pasgrimaud <gael@gawel.org>

## Status & License

WebTest is an extraction of `paste.fixture.TestApp`, rewriting portions to use WebOb. It is under active development as part of the Pylons cloud of packages.

Feedback and discussion should take place on the Pylons discuss list, and bugs should go into the Github tracker.

This library is licensed under an MIT-style license.

## Installation

You can use pip or easy_install to get the latest stable release:

    $ pip install WebTest
    $ easy_install WebTest

Or if you want the development version:

    $ pip install https://nodeload.github.com/Pylons/webtest/tar.gz/main

## What This Does

WebTest helps you test your WSGI-based web applications. This can be any application that has a WSGI interface, including an application written in a framework that supports WSGI (which includes most actively developed Python web frameworks -- almost anything that even nominally supports WSGI should be testable).

With this you can test your web applications without starting an HTTP server, and without poking into the web framework shortcutting pieces of your application that need to be tested. The tests WebTest runs are entirely equivalent to how a WSGI HTTP server would call an application. By testing the full stack of your application, the WebTest testing model is sometimes called a functional test, integration test, or acceptance test (though the latter two are not particularly good descriptions). This is in contrast to a unit test which tests a particular piece of functionality in your application. While complex programming tasks are often suited to unit tests, template logic and simple web programming is often best done with functional tests; and regardless of the presence of unit tests, no testing strategy is complete without high-level tests to ensure the entire programming system works together.

WebTest helps you create tests by providing a convenient interface to run WSGI applications and verify the output.

## Quick start

The most important object in WebTest is `TestApp`, the wrapper for WSGI applications. It also allows you to perform HTTP requests on it. To use it, you simply instantiate it with your WSGI application.

Note

If your WSGI application requires any configuration, you must set that up manually in your tests.

Here is a basic application:

    >>> def application(environ, start_response):
    ...     headers = [('Content-Type', 'text/html; charset=utf8'),
    ...                ('Content-Length', str(len(body)))]
    ...     start_response('200 OK', headers)
    ...     return [body]

Wrap it into a `TestApp`:

    >>> from webtest import TestApp
    >>> app = TestApp(application)

Then you can get the response of a HTTP GET:

    >>> resp = app.get('/')

And check the results, like response's status:

    >>> assert resp.status == '200 OK'
    >>> assert resp.status_int == 200

Response's headers:

    >>> assert resp.content_type == 'text/html'
    >>> assert resp.content_length > 0

Or response's body:

    >>> resp.mustcontain('<html>')
    >>> assert 'form' in resp

WebTest can do much more. In particular, it can handle Form handling.

## Contents

- Functional Testing of Web Applications
  - TestApp
    - Making Requests
    - Making JSON Requests
    - Modifying the Environment & Simulating Authentication
    - Testing a non wsgi application
    - What Is Tested By Default
  - TestResponse
    - Form handling
      - Getting a form
      - Filling a form
      - Field types
        - Input and textarea fields
        - Select fields
        - `Checkbox`
        - Radio
        - File
      - Submit a form
    - Parsing the Body
  - WSGI Debug application
  - Framework Hooks
- `webtest` API
  - `webtest.app.TestApp`
    - `TestApp`
      - `TestApp.cookies`
      - `TestApp.RequestClass`
      - `TestApp.authorization`
      - `TestApp.delete()`
      - `TestApp.delete_json()`
      - `TestApp.do_request()`
      - `TestApp.encode_multipart()`
      - `TestApp.get()`
      - `TestApp.get_authorization()`
      - `TestApp.head()`
      - `TestApp.options()`
      - `TestApp.patch()`
      - `TestApp.patch_json()`
      - `TestApp.post()`
      - `TestApp.post_json()`
      - `TestApp.put()`
      - `TestApp.put_json()`
      - `TestApp.request()`
      - `TestApp.reset()`
      - `TestApp.set_cookie()`
      - `TestApp.set_parser_features()`
  - `webtest.app.TestRequest`
    - `TestRequest`
      - `TestRequest.ResponseClass`
  - `webtest.response.TestResponse`
    - `TestResponse`
      - `TestResponse.PyQuery()`
      - `TestResponse.click()`
      - `TestResponse.clickbutton()`
      - `TestResponse.follow()`
      - `TestResponse.form`
      - `TestResponse.forms`
      - `TestResponse.goto()`
      - `TestResponse.html`
      - `TestResponse.json`
      - `TestResponse.lxml`
      - `TestResponse.maybe_follow()`
      - `TestResponse.mustcontain()`
      - `TestResponse.normal_body`
      - `TestResponse.pyquery`
      - `TestResponse.showbrowser()`
      - `TestResponse.unicode_normal_body`
      - `TestResponse.xml`
  - `webtest.forms`
    - `Checkbox`
      - `Checkbox.checked`
      - `Checkbox.force_value()`
    - `Email`
      - `Email.force_value()`
    - `Field`
      - `Field.classes`
      - `Field.value`
      - `Field.force_value()`
    - `File`
      - `File.force_value()`
    - `Form`
      - `Form.text`
      - `Form.action`
      - `Form.method`
      - `Form.id`
      - `Form.enctype`
      - `Form.fields`
      - `Form.field_order`
      - `Form.FieldClass`
      - `Form.get()`
      - `Form.lint()`
      - `Form.select()`
      - `Form.select_multiple()`
      - `Form.set()`
      - `Form.submit()`
      - `Form.submit_fields()`
      - `Form.upload_fields()`
    - `Hidden`
      - `Hidden.force_value()`
    - `MultipleSelect`
      - `MultipleSelect.force_value()`
    - `Radio`
      - `Radio.force_value()`
    - `Select`
      - `Select.force_value()`
    - `Submit`
      - `Submit.force_value()`
    - `Text`
      - `Text.force_value()`
    - `Textarea`
      - `Textarea.force_value()`
    - `Upload`
  - `webtest.http`
    - `StopableWSGIServer`
      - `StopableWSGIServer.create()`
      - `StopableWSGIServer.run()`
      - `StopableWSGIServer.shutdown()`
      - `StopableWSGIServer.wait()`
      - `StopableWSGIServer.wrapper()`
    - `check_server()`
  - `webtest.lint`
    - `middleware()`
  - `webtest.debugapp`
    - `DebugApp`
    - `make_debug_app()`
- Contribute to webtest project
  - Getting started
  - Execute tests
  - Use tox to test many Python versions
  - Generate documentation
  - Tips
- News
  - 3.0.7 (2025-10-06)
  - 3.0.6 (2025-06-04)
  - 3.0.5 (2025-06-04)
  - 3.0.4 (2025-02-03)
  - 3.0.3 (2025-01-16)
  - 3.0.2 (2024-11-27)
  - 3.0.1 (2024-08-30)
  - 3.0.0 (2021-08-19)
  - 2.0.35 (2020-04-27)
  - 2.0.34 (2020-01-29)
  - 2.0.33 (2019-02-09)
  - 2.0.32 (2018-10-05)
  - 2.0.31 (2018-10-05)
  - 2.0.30 (2018-06-23)
  - 2.0.29 (2017-10-21)
  - 2.0.28 (2017-08-01)
  - 2.0.27 (2017-03-15)
  - 2.0.26 (2017-03-05)
  - 2.0.25 (2017-02-05)
  - 2.0.24 (2016-12-16)
  - 2.0.23 (2016-07-21)
  - 2.0.22 (2016-07-21)
  - 2.0.21 (2016-04-12)
  - 2.0.20 (2015-11-03)
  - 2.0.19 (2015-11-01)
  - 2.0.18 (2015-02-05)
  - 2.0.17 (2014-12-20)
  - 2.0.16 (2014-09-19)
  - 2.0.15 (2014-04-17)
  - 2.0.14 (2014-01-23)
  - 2.0.13 (2014-01-23)
  - 2.0.12 (2014-01-17)
  - 2.0.11 (2013-12-29)
  - 2.0.10 (2013-11-14)
  - 2.0.9 (2013-09-18)
  - 2.0.8 (2013-09-17)
  - 2.0.7 (2013-08-07)
  - 2.0.6 (2013-05-23)
  - 2.0.5 (2013-04-12)
  - 2.0.4 (2013-03-28)
  - 2.0.3 (2013-03-19)
  - 2.0.2 (2013-03-15)
  - 2.0.1 (2013-03-05)
  - 2.0 (2013-02-25)
  - 1.4.2
  - 1.4.1
  - 1.4.0
  - 1.3.6
  - 1.3.5
  - 1.3.4
  - 1.3.3
  - 1.3.2
  - 1.3.1
  - 1.3
  - 1.2.4
  - 1.2.3
  - 1.2.2
  - 1.2.1
  - 1.2
  - 1.1
  - 1.0.2
  - 1.0
  - 0.9

## License

Copyright (c) 2010 Ian Bicking and Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.