
It is possible to inject a wsgi stack by subclassing from BrowserLayer:

First, create and register a view to test:

    >>> from zope import component, interface
    >>> from zope.app.wsgi.testing import IndexView
    >>> component.provideAdapter(IndexView, name='index.html')
    >>> from zope.security import checker
    >>> checker.defineChecker(
    ...     IndexView,
    ...     checker.NamesChecker(['browserDefault', '__call__']),
    ...     )
    >>> from zope.app.wsgi.testing import ErrorRaisingView
    >>> component.provideAdapter(ErrorRaisingView, name='error.html')
    >>> checker.defineChecker(
    ...     ErrorRaisingView,
    ...     checker.NamesChecker(['browserDefault', '__call__']),
    ...     )

The `silly middleware` has injected information into the page:

    >>> from webtest.app import TestApp
    >>> browser = TestApp(wsgi_app)
    >>> res = browser.get('http://localhost/index.html')
    >>> print(res.html)
    <html>
      <head>
      </head>
      <body><h1>Hello from the silly middleware</h1>
        <p>This is the index</p>
      </body>
    </html>

The default behavior of the browser is to handle errors::

    >>> browser.get('http://localhost/error.html') \
    ...     #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ...
    AppError: Bad response: 500 Internal Server Error

One can set error handling behavior::

    >>> browser = TestApp(wsgi_app, extra_environ={'wsgi.handleErrors': False})
    >>> browser.get('http://localhost/error.html') \
    ...     #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ...
    ZeroDivisionError: integer division or modulo by zero

The http caller is more low level than the Browser.

    >>> from zope.app.wsgi.testlayer import http
    >>> response = http(wsgi_app, b'GET /index.html HTTP/1.0')
    >>> print(response)  #doctest: +ELLIPSIS
    HTTP/1.0 200 Ok
    Content-Type: text/html...
    ...Hello from the silly middleware...

It exposes the same error handling parameter:

    >>> response = http(wsgi_app, b'GET /error.html HTTP/1.1')
    >>> response.getStatus() == 500
    True
    >>> http(wsgi_app, b'GET /error.html HTTP/1.1', handle_errors=False) \
    ...     #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ...
    ZeroDivisionError: integer division or modulo by zero

It passes through the request protocol as the response protocol:

    >>> response = http(wsgi_app, b'GET /index.html HTTP/1.1')
    >>> print(response)  #doctest: +ELLIPSIS
    HTTP/1.1 200 Ok
    Content-Type: text/html...
    ...Hello from the silly middleware...

Clean up:

    >>> import zope.publisher.interfaces.browser
    >>> checker.undefineChecker(IndexView)
    >>> component.provideAdapter(
    ...     None,
    ...     (interface.Interface,
    ...     zope.publisher.interfaces.browser.IBrowserRequest),
    ...     zope.publisher.interfaces.browser.IBrowserPublisher,
    ...     'index.html',
    ...     )
    >>> checker.undefineChecker(ErrorRaisingView)
    >>> component.provideAdapter(
    ...     None,
    ...     (interface.Interface,
    ...     zope.publisher.interfaces.browser.IBrowserRequest),
    ...     zope.publisher.interfaces.browser.IBrowserPublisher,
    ...     'error.html',
    ...     )
