Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/lugensa/gocept.httpserverlayer
This package provides an HTTP server for testing your application with normal HTTP clients (e.g. a real browser). This is done using `test layers`, which are a feature of `zope.testrunner`.
https://github.com/lugensa/gocept.httpserverlayer
http python testing testrunner
Last synced: about 1 month ago
JSON representation
This package provides an HTTP server for testing your application with normal HTTP clients (e.g. a real browser). This is done using `test layers`, which are a feature of `zope.testrunner`.
- Host: GitHub
- URL: https://github.com/lugensa/gocept.httpserverlayer
- Owner: lugensa
- License: other
- Created: 2019-08-27T07:07:16.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2023-10-09T06:30:08.000Z (over 1 year ago)
- Last Synced: 2024-11-29T16:53:31.212Z (about 1 month ago)
- Topics: http, python, testing, testrunner
- Language: Python
- Homepage:
- Size: 629 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.rst
- Changelog: CHANGES.rst
- License: LICENSE.txt
Awesome Lists containing this project
README
======================
gocept.httpserverlayer
======================This package provides an HTTP server for testing your application with normal
HTTP clients (e.g. a real browser). This is done using `test layers`_, which
are a feature of `zope.testrunner`_.gocept.httpserverlayer uses `plone.testing`_ for the test layer implementation,
and exposes the following resources (accessible in your test case as
``self.layer[RESOURCE_NAME]``)::http_host: The hostname of the HTTP server (Default: localhost)
:http_port: The port of the HTTP server (Default: 0, which means chosen
automatically by the operating system)
:http_address: ``hostname:port``, convenient to use in URLs
(e.g. ``'http://user:password@%s/path' % self.layer['http_address']``)This package is compatible with Python version 3.6, 3.7, 3.8, and 3.9.
.. _`test layers`: https://pypi.org/project/plone.testing/#layers
.. _`zope.testrunner`: https://pypi.org/project/zope.testrunner/
.. _`plone.testing`: https://pypi.org/project/plone.testing/.. contents::
WSGI
====This test layer takes a WSGI callable and runs it in a temporary HTTP server::
import gocept.httpserverlayer.wsgi
from mypackage import App
import unittestHTTP_LAYER = gocept.httpserverlayer.wsgi.Layer()
HTTP_LAYER.wsgi_app = App()class WSGIExample(unittest.TestCase):
layer = HTTP_LAYER
def test_something(self):
r = urllib.urlopen('http://{0.layer[http_address]}/'.format(self))
self.assertIn('Hello world', r.read())You can also have a base layer provide the WSGI callable (in the
``wsgi_app`` resource)::import gocept.httpserverlayer.wsgi
from mypackage import App
import plone.testingclass WSGILayer(plone.testing.Layer):
def setUp(self):
self['wsgi_app'] = App()WSGI_LAYER = WSGILayer()
HTTP_LAYER = gocept.httpserverlayer.wsgi.Layer(
name='HTTPLayer', bases=(WSGI_LAYER,))Static files
============This test layer serves up the contents of a directory::
import gocept.httpserverlayer.static
import pkg_resources
import unittestHTTP_LAYER = gocept.httpserverlayer.static.Layer(
pkg_resources.resource_filename('my.package.tests', 'fixtures'))class DirecoryExample(unittest.TestCase):
layer = HTTP_LAYER
def test_something(self):
r = urllib.urlopen('http://{0.layer[http_address]}/'.format(self))
self.assertIn('Hello world', r.read())If you don't pass in a directory, a temporary directory will be created/removed
automatically. The directory is provided in the ``documentroot`` resource.
For convenience, a layer instance is already provided as ``STATIC_FILES``::import gocept.httpserverlayer.static
import os.path
import unittestHTTP_LAYER = gocept.httpserverlayer.static.STATIC_FILES
class TemporaryExample(unittest.TestCase):
layer = HTTP_LAYER
def test_something(self):
path = os.path.join(self.testlayer['documentroot'], 'index')
with open(path, 'w') as f:
f.write('Hello World!')
r = urllib.urlopen(
'http://{0.layer[http_address]}/index'.format(self))
self.assertIn('Hello world', r.read())Custom request handler
======================This test layer allows you to provide your own HTTP request handler for very
fine-grained control::import gocept.httpserverlayer.custom
import unittestclass RequestHandler(gocept.httpserverlayer.custom.RequestHandler):
response_code = 200
response_body = ''
posts_received = []def do_POST(self):
length = int(self.headers['content-length'])
self.posts_received.append(dict(
path=self.path,
data=self.rfile.read(length),
headers=self.headers,
))
self.send_response(self.response_code)
self.end_headers()
self.wfile.write(self.response_body)HTTP_LAYER = gocept.httpserverlayer.custom.Layer(RequestHandler)
class POSTExample(unittest.TestCase):
layer = HTTP_LAYER
def test_something(self):
urllib.urlopen('http://{0.layer[http_address]}/'.format(self),
urllib.urlencode({'foo': 'bar'}))
self.assertEqual(
'foo=bar',
self.layer['request_handler'].posts_received[0]['data'])Framework integration
=====================gocept.httpserverlayer also provides integration with some web frameworks.
Different frameworks require different dependencies; this is handled via
setuptools extras of gocept.httpserverlayer (e.g. for Grok integration you need
to require ``gocept.httpserverlayer[zopeappwsgi]``).Zope 3 / ZTK / Grok (zope.app.wsgi)
===================================Requires ``gocept.httpserverlayer[zopeappwsgi]``
If your ZTK application uses ``zope.app.wsgi.testlayer`` (which is the
recommended test setup for Grok, for example), you can use
``gocept.httpserverlayer.zopeappwsgi.Layer`` to create a WSGI app that
integrates ZODB isolation, and ``gocept.httpserverlayer.wsgi.Layer`` to provide
the actual HTTP server. No special TestCase is required, ``unittest.TestCase``
is enough.The ``zopeappwsgi.Layer`` expects to find the current ZODB in the plone.testing
resource ``zodbDB`` (which is used by ``plone.testing.zodb.EMPTY_ZODB``), or
you can inherit and override ``get_current_zodb``. Here's an example setup for
Grok (which uses ``zope.app.appsetup.testlayer.ZODBLayer``)::import gocept.httpserverlayer.wsgi
import gocept.httpserverlayer.zopeappwsgi
import unittest
import zope.app.appsetup.testlayerZODB_LAYER = zope.app.appsetup.testlayer.ZODBLayer(
gocept.httpserverlayer.zopeappwsgi, 'testing.zcml')class WSGILayer(gocept.httpserverlayer.zopeappwsgi.Layer):
defaultBases = (ZODB_LAYER,)
def get_current_zodb(self):
return ZODB_LAYER.dbWSGI_LAYER = WSGILayer()
HTTP_LAYER = gocept.httpserverlayer.wsgi.Layer(
name='HTTPLayer', bases=(WSGI_LAYER,))class GrokExample(unittest.TestCase):
layer = HTTP_LAYER
def test(self):
r = urllib.urlopen('http://%s/' % self.layer['http_address'])
self.assertIn('Hello world', r.read())Zope via WSGI
=============If your Zope setup supports WSGI, you can use the WSGI integration instead of a
specialised Zope integration to run your tests.You might see an exception complaining about the ``Connection`` header.
To fix this issue you can use an additional middleware around your WSGI
application: ``gocept.httpserverlayer.wsgi.FixupMiddleware``.Zope / Plone via `plone.testing.zope`
=====================================Requires ``gocept.httpserverlayer[plonetestingzope]``.
gocept.httpserverlayer provides a ``plone.testing.Layer`` at
``gocept.httpserverlayer.plonetestingzope.HTTP_SERVER`` that you can mix and match
with your base layers. No special TestCase is required, ``unittest.TestCase``
is enough... caution:: This setup also uses the WSGI flavour instead of ZServer which
was supported in `gocept.httpserverlayer < 3`.For a plain Zope application this might look like this (uses
``plone.testing[zope]``)::import gocept.httpserverlayer.plonetestingzope
import plone.testing
import plone.testing.zopeclass Layer(plone.testing.Layer):
defaultBases = (plone.testing.zope.STARTUP,)
def setUp(self):
zope.configuration.xmlconfig.file(
'testing.zcml', package=mypackage,
context=self['configurationContext'])ZOPE_LAYER = Layer()
HTTP_LAYER = plone.testing.Layer(
name='HTTPLayer',
bases=(ZOPE_LAYER,
gocept.httpserverlayer.plonetestingzope.HTTP_SERVER))