Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fixes issue 1001. #1186

Closed
wants to merge 1 commit into from

3 participants

@mgrbyte

Provides sample source code for integration and functional tests.
Moved credit to Ian Bicking for WebTest to glossary.

@mgrbyte mgrbyte Fixes issues 1001.
Provides sample source code for integration and functional tests.
Moved credit to Ian Bicking for WebTest to glossary.
dbe6bd3
@mgrbyte

Wondering if someone could provide some feedback on this one?
If there's anything more I can do here, please let me know.

@mcdonc
Owner

Sorry Matthew for the radio silence on this. I'll review soon.

@mgrbyte

Thanks Chris!

I think the actually doc changes themselves OK, not so sure about the inclusion of all the files the scaffold generates in necessary. Possibly better to just include the python files that define the tests and reduce bloat.

@tseaver
Owner

@mgrbyte +1 for excluding the scaffold files which are not pulled into Sphinx via .. literalinclude:: (i.e., setup.py, myapp/views.py, and myapp/tests.py).

@mgrbyte

@tseaver I'll see if I can reboot this one later on, thanks

@mgrbyte

@tseaver I created #1467 to replace this PR, closing.

@mgrbyte mgrbyte closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 13, 2013
  1. @mgrbyte

    Fixes issues 1001.

    mgrbyte authored
    Provides sample source code for integration and functional tests.
    Moved credit to Ian Bicking for WebTest to glossary.
This page is out of date. Refresh to see the latest.
View
3  docs/glossary.rst
@@ -860,7 +860,8 @@ Glossary
WebTest
`WebTest <http://pythonpaste.org/webtest/>`_ is a package which can help
- you write functional tests for your WSGI application.
+ you write functional tests for your WSGI application, developed
+ by Ian Bicking.
view mapper
A view mapper is a class which implements the
View
4 docs/narr/src/myapp/CHANGES.txt
@@ -0,0 +1,4 @@
+0.0
+---
+
+- Initial version
View
2  docs/narr/src/myapp/MANIFEST.in
@@ -0,0 +1,2 @@
+include *.txt *.ini *.cfg *.rst
+recursive-include myapp *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml
View
6 docs/narr/src/myapp/README.txt
@@ -0,0 +1,6 @@
+README
+======
+
+This is an example application used to demonstrate
+basic testing in Pyrmaid application.
+
View
60 docs/narr/src/myapp/development.ini
@@ -0,0 +1,60 @@
+###
+# app configuration
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
+###
+
+[app:main]
+use = egg:myapp
+
+pyramid.reload_templates = true
+pyramid.debug_authorization = false
+pyramid.debug_notfound = false
+pyramid.debug_routematch = false
+pyramid.default_locale_name = en
+pyramid.includes =
+ pyramid_debugtoolbar
+
+# By default, the toolbar only appears for clients from IP addresses
+# '127.0.0.1' and '::1'.
+# debugtoolbar.hosts = 127.0.0.1 ::1
+
+###
+# wsgi server configuration
+###
+
+[server:main]
+use = egg:waitress#main
+host = 0.0.0.0
+port = 6543
+
+###
+# logging configuration
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
+###
+
+[loggers]
+keys = root, myapp
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_myapp]
+level = DEBUG
+handlers =
+qualname = myapp
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
View
17 docs/narr/src/myapp/myapp/__init__.py
@@ -0,0 +1,17 @@
+from pyramid.config import Configurator
+
+
+def main(global_config, **settings):
+ """ This function returns a Pyramid WSGI application.
+ """
+ config = Configurator(settings=settings)
+ config = includeme(config)
+ return config.make_wsgi_app()
+
+
+def includeme(config):
+ config.include('pyramid_chameleon')
+ config.add_static_view('static', 'static', cache_max_age=3600)
+ config.add_route('home', '/')
+ config.scan()
+ return config
View
BIN  docs/narr/src/myapp/myapp/static/favicon.ico
Binary file not shown
View
BIN  docs/narr/src/myapp/myapp/static/footerbg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  docs/narr/src/myapp/myapp/static/headerbg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
8 docs/narr/src/myapp/myapp/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
View
BIN  docs/narr/src/myapp/myapp/static/middlebg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
372 docs/narr/src/myapp/myapp/static/pylons.css
@@ -0,0 +1,372 @@
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+h2
+{
+ font-size: 1.5em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+h3
+{
+ font-size: 1.25em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+h4
+{
+ font-size: 1em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+html, body
+{
+ width: 100%;
+ height: 100%;
+}
+
+body
+{
+ margin: 0;
+ padding: 0;
+ background-color: #fff;
+ position: relative;
+ font: 16px/24px NobileRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+}
+
+a
+{
+ color: #1b61d6;
+ text-decoration: none;
+}
+
+a:hover
+{
+ color: #e88f00;
+ text-decoration: underline;
+}
+
+body h1, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 url(footerbg.png) repeat-x 0 top;
+ position: relative;
+ margin-top: -40px;
+ clear: both;
+}
+
+.header, .footer
+{
+ width: 750px;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+.wrapper
+{
+ width: 100%;
+}
+
+#top, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.top, .top-small, .middle, .bottom
+{
+ width: 750px;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+.top
+{
+ padding-top: 40px;
+}
+
+.top-small
+{
+ padding-top: 10px;
+}
+
+#middle
+{
+ width: 100%;
+ height: 100px;
+ background: url(middlebg.png) repeat-x;
+ border-top: 2px solid #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+ul.links li
+{
+ list-style-type: none;
+ font-size: 14px;
+}
+
+form
+{
+ border-style: none;
+}
+
+fieldset
+{
+ border-style: none;
+}
+
+input
+{
+ color: #222;
+ border: 1px solid #ccc;
+ font-family: sans-serif;
+ font-size: 12px;
+ line-height: 16px;
+}
+
+input[type=text], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
+/*Opera Fix*/
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
View
BIN  docs/narr/src/myapp/myapp/static/pyramid.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  docs/narr/src/myapp/myapp/static/transparent.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
73 docs/narr/src/myapp/myapp/templates/mytemplate.pt
@@ -0,0 +1,73 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
+<head>
+ <title>The Pyramid Web Framework</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon" href="${request.static_url('myapp:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('myapp:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
+ <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('myapp:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
+</head>
+<body>
+ <div id="wrap">
+ <div id="top">
+ <div class="top align-center">
+ <div><img src="${request.static_url('myapp:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
+ <p class="app-welcome">
+ Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
+ the ${framework} Web Framework.
+ </p>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div id="left" class="align-right">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
+ </div>
+ <div id="right" class="align-left">
+ <h2>Pyramid links</h2>
+ <ul class="links">
+ <li>
+ <a href="http://pylonsproject.org">Pylons Website</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#narrative-documentation">Narrative Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#reference-material">API Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#tutorials">Tutorials</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#detailed-change-history">Change History</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#sample-applications">Sample Applications</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#support-and-development">Support and Development</a>
+ </li>
+ <li>
+ <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
View
40 docs/narr/src/myapp/myapp/tests.py
@@ -0,0 +1,40 @@
+import unittest
+
+from pyramid import testing
+
+class ViewIntegrationTests(unittest.TestCase):
+ def setUp(self):
+ """ This sets up the application registry with the
+ registrations your application declares in its ``includeme``
+ function.
+ """
+ self.config = testing.setUp()
+ self.config.include('myapp')
+
+ def tearDown(self):
+ """ Clear out the application registry """
+ testing.tearDown()
+
+ def test_my_view(self):
+ from myapp.views import my_view
+ request = testing.DummyRequest()
+ result = my_view(request)
+ self.assertEqual(result.status, '200 OK')
+ body = result.app_iter[0]
+ self.assertTrue('Welcome to' in body)
+ self.assertEqual(len(result.headerlist), 2)
+ self.assertEqual(result.headerlist[0],
+ ('Content-Type', 'text/html; charset=UTF-8'))
+ self.assertEqual(result.headerlist[1], ('Content-Length',
+ str(len(body))))
+
+class FunctionalTests(unittest.TestCase):
+ def setUp(self):
+ from myapp import main
+ app = main({})
+ from webtest import TestApp
+ self.testapp = TestApp(app)
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertTrue('Pyramid' in res.body)
View
9 docs/narr/src/myapp/myapp/views.py
@@ -0,0 +1,9 @@
+from pyramid.view import view_config
+
+@view_config(route_name='my_view', renderer='string')
+def my_view(request):
+ return 'Welcome to this application'
+
+@view_config(route_name='home', renderer='mytemplate.pt')
+def home_view(request):
+ return {'framework': 'Pyramid', 'project': 'myapp'}
View
54 docs/narr/src/myapp/production.ini
@@ -0,0 +1,54 @@
+###
+# app configuration
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
+###
+
+[app:main]
+use = egg:myapp
+
+pyramid.reload_templates = false
+pyramid.debug_authorization = false
+pyramid.debug_notfound = false
+pyramid.debug_routematch = false
+pyramid.default_locale_name = en
+
+###
+# wsgi server configuration
+###
+
+[server:main]
+use = egg:waitress#main
+host = 0.0.0.0
+port = 6543
+
+###
+# logging configuration
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
+###
+
+[loggers]
+keys = root, myapp
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+
+[logger_myapp]
+level = WARN
+handlers =
+qualname = myapp
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
View
27 docs/narr/src/myapp/setup.cfg
@@ -0,0 +1,27 @@
+[nosetests]
+match = ^test
+nocapture = 1
+cover-package = myapp
+with-coverage = 1
+cover-erase = 1
+
+[compile_catalog]
+directory = myapp/locale
+domain = myapp
+statistics = true
+
+[extract_messages]
+add_comments = TRANSLATORS:
+output_file = myapp/locale/myapp.pot
+width = 80
+
+[init_catalog]
+domain = myapp
+input_file = myapp/locale/myapp.pot
+output_dir = myapp/locale
+
+[update_catalog]
+domain = myapp
+input_file = myapp/locale/myapp.pot
+output_dir = myapp/locale
+previous = true
View
42 docs/narr/src/myapp/setup.py
@@ -0,0 +1,42 @@
+import os
+
+from setuptools import setup, find_packages
+
+here = os.path.abspath(os.path.dirname(__file__))
+with open(os.path.join(here, 'README.txt')) as f:
+ README = f.read()
+with open(os.path.join(here, 'CHANGES.txt')) as f:
+ CHANGES = f.read()
+
+requires = [
+ 'pyramid',
+ 'pyramid_chameleon',
+ 'pyramid_debugtoolbar',
+ 'waitress',
+ ]
+
+setup(name='myapp',
+ version='0.0',
+ description='myapp',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ "Programming Language :: Python",
+ "Framework :: Pyramid",
+ "Topic :: Internet :: WWW/HTTP",
+ "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=requires,
+ tests_require=requires + ['WebTest'],
+ test_suite="myapp",
+ entry_points="""\
+ [paste.app_factory]
+ main = myapp:main
+ """,
+ )
View
93 docs/narr/testing.rst
@@ -346,45 +346,25 @@ your application was running "for real". This is a heavy-hammer way of
making sure that your tests have enough context to run properly, and it tests
your code's integration with the rest of :app:`Pyramid`.
-Let's demonstrate this by showing an integration test for a view. The below
-test assumes that your application's package name is ``myapp``, and that
-there is a ``views`` module in the app with a function with the name
-``my_view`` in it that returns the response 'Welcome to this application'
-after accessing some values that require a fully set up environment.
+Let's demonstrate this by showing an integration test for a view.
-.. code-block:: python
- :linenos:
+Given the following view definition, which assumes that your application's
+:term:`package` name is ``myapp``, and within that :term:`package` there
+exists a module ``views``, which in turn contains a :term:`view`
+function named ``my_view``:
- import unittest
-
- from pyramid import testing
+ .. literalinclude:: src/myapp/myapp/views.py
+ :linenos:
+ :lines: 1-6
+ :language: python
- class ViewIntegrationTests(unittest.TestCase):
- def setUp(self):
- """ This sets up the application registry with the
- registrations your application declares in its ``includeme``
- function.
- """
- import myapp
- self.config = testing.setUp()
- self.config.include('myapp')
-
- def tearDown(self):
- """ Clear out the application registry """
- testing.tearDown()
+You'd then create a ``tests`` module within your ``myapp`` package, containing
+the following test code:
- def test_my_view(self):
- from myapp.views import my_view
- request = testing.DummyRequest()
- result = my_view(request)
- self.assertEqual(result.status, '200 OK')
- body = result.app_iter[0]
- self.assertTrue('Welcome to' in body)
- self.assertEqual(len(result.headerlist), 2)
- self.assertEqual(result.headerlist[0],
- ('Content-Type', 'text/html; charset=UTF-8'))
- self.assertEqual(result.headerlist[1], ('Content-Length',
- str(len(body))))
+ .. literalinclude:: src/myapp/myapp/tests.py
+ :linenos:
+ :pyobject: ViewIntegrationTests
+ :language: python
Unless you cannot avoid it, you should prefer writing unit tests that use the
:class:`~pyramid.config.Configurator` API to set up the right "mock"
@@ -402,27 +382,34 @@ Creating Functional Tests
Functional tests test your literal application.
-The below test assumes that your application's package name is ``myapp``, and
-that there is a view that returns an HTML body when the root URL is invoked.
-It further assumes that you've added a ``tests_require`` dependency on the
-``WebTest`` package within your ``setup.py`` file. :term:`WebTest` is a
-functional testing package written by Ian Bicking.
+In Pyramid, functional tests are typically written using the :term:`WebTest`
+package.
-.. code-block:: python
- :linenos:
+Regardless of which testing :term:`package` you use, ensure to add
+a ``tests_require`` dependancy on that package to to your application's
+``setup.py`` file:
- import unittest
+ .. literalinclude:: src/myapp/setup.py
+ :linenos:
+ :emphasize-lines: 36
+ :language: python
- class FunctionalTests(unittest.TestCase):
- def setUp(self):
- from myapp import main
- app = main({})
- from webtest import TestApp
- self.testapp = TestApp(app)
-
- def test_root(self):
- res = self.testapp.get('/', status=200)
- self.assertTrue('Pyramid' in res.body)
+Assuming your :term:`package` is named ``myapp``, which
+contains a ``views`` module, which in turn contains a :term:`view`
+function ``home_view`` that returns a HTML body when the root URL is invoked:
+
+ .. literalinclude:: src/myapp/myapp/views.py
+ :linenos:
+ :lines: 1, 7-10
+ :language: python
+
+Then the following example functional test (shown below) demonstrates invoking
+the :term:`view` shown above:
+
+ .. literalinclude:: src/myapp/myapp/tests.py
+ :linenos:
+ :pyobject: FunctionalTests
+ :language: python
When this test is run, each test creates a "real" WSGI application using the
``main`` function in your ``myapp.__init__`` module and uses :term:`WebTest`
Something went wrong with that request. Please try again.