diff options
| author | Steve Piercy <web@stevepiercy.com> | 2020-01-08 02:00:20 -0800 |
|---|---|---|
| committer | Steve Piercy <web@stevepiercy.com> | 2020-01-08 02:00:20 -0800 |
| commit | 3630b1ebd981a994b83689a6becb9922f1b20f0a (patch) | |
| tree | 7fe2c695957730bc5251b70761ea3c54c5667b9d /docs/narr | |
| parent | 14403a3f6d7cb870aefafa6bfa8999f86aa29c86 (diff) | |
| download | pyramid-3630b1ebd981a994b83689a6becb9922f1b20f0a.tar.gz pyramid-3630b1ebd981a994b83689a6becb9922f1b20f0a.tar.bz2 pyramid-3630b1ebd981a994b83689a6becb9922f1b20f0a.zip | |
sync cookiecutter to starter project `myproject`
Diffstat (limited to 'docs/narr')
| -rw-r--r-- | docs/narr/myproject/.gitignore | 1 | ||||
| -rw-r--r-- | docs/narr/myproject/testing.ini | 53 | ||||
| -rw-r--r-- | docs/narr/myproject/tests/conftest.py | 69 | ||||
| -rw-r--r-- | docs/narr/myproject/tests/test_functional.py | 7 | ||||
| -rw-r--r-- | docs/narr/myproject/tests/test_it.py | 39 | ||||
| -rw-r--r-- | docs/narr/myproject/tests/test_views.py | 13 | ||||
| -rw-r--r-- | docs/narr/project.rst | 47 | ||||
| -rw-r--r-- | docs/narr/testing.rst | 23 |
8 files changed, 195 insertions, 57 deletions
diff --git a/docs/narr/myproject/.gitignore b/docs/narr/myproject/.gitignore index 1853d983c..c612e59f2 100644 --- a/docs/narr/myproject/.gitignore +++ b/docs/narr/myproject/.gitignore @@ -19,3 +19,4 @@ Data.fs* .DS_Store coverage test +*.sqlite diff --git a/docs/narr/myproject/testing.ini b/docs/narr/myproject/testing.ini new file mode 100644 index 000000000..f2ef86805 --- /dev/null +++ b/docs/narr/myproject/testing.ini @@ -0,0 +1,53 @@ +### +# app configuration +# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:myproject + +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 +listen = localhost:6543 + +### +# logging configuration +# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### + +[loggers] +keys = root, myproject + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_myproject] +level = DEBUG +handlers = +qualname = myproject + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s diff --git a/docs/narr/myproject/tests/conftest.py b/docs/narr/myproject/tests/conftest.py new file mode 100644 index 000000000..296205927 --- /dev/null +++ b/docs/narr/myproject/tests/conftest.py @@ -0,0 +1,69 @@ +import os +from pyramid.paster import get_appsettings +from pyramid.scripting import prepare +from pyramid.testing import DummyRequest +import pytest +import webtest + +from myproject import main + + +def pytest_addoption(parser): + parser.addoption('--ini', action='store', metavar='INI_FILE') + +@pytest.fixture(scope='session') +def ini_file(request): + # potentially grab this path from a pytest option + return os.path.abspath(request.config.option.ini or 'testing.ini') + +@pytest.fixture(scope='session') +def app_settings(ini_file): + return get_appsettings(ini_file) + +@pytest.fixture(scope='session') +def app(app_settings): + return main({}, **app_settings) + +@pytest.fixture +def testapp(app): + testapp = webtest.TestApp(app, extra_environ={ + 'HTTP_HOST': 'example.com', + }) + + return testapp + +@pytest.fixture +def app_request(app): + """ + A real request. + + This request is almost identical to a real request but it has some + drawbacks in tests as it's harder to mock data and is heavier. + + """ + env = prepare(registry=app.registry) + request = env['request'] + request.host = 'example.com' + + yield request + env['closer']() + +@pytest.fixture +def dummy_request(app): + """ + A lightweight dummy request. + + This request is ultra-lightweight and should be used only when the + request itself is not a large focus in the call-stack. + + It is way easier to mock and control side-effects using this object. + + - It does not have request extensions applied. + - Threadlocals are not properly pushed. + + """ + request = DummyRequest() + request.registry = app.registry + request.host = 'example.com' + + return request diff --git a/docs/narr/myproject/tests/test_functional.py b/docs/narr/myproject/tests/test_functional.py new file mode 100644 index 000000000..bac5d63f4 --- /dev/null +++ b/docs/narr/myproject/tests/test_functional.py @@ -0,0 +1,7 @@ +def test_root(testapp): + res = testapp.get('/', status=200) + assert b'Pyramid' in res.body + +def test_notfound(testapp): + res = testapp.get('/badurl', status=404) + assert res.status_code == 404 diff --git a/docs/narr/myproject/tests/test_it.py b/docs/narr/myproject/tests/test_it.py deleted file mode 100644 index b300da34d..000000000 --- a/docs/narr/myproject/tests/test_it.py +++ /dev/null @@ -1,39 +0,0 @@ -import unittest - -from pyramid import testing - - -class ViewTests(unittest.TestCase): - def setUp(self): - self.config = testing.setUp() - - def tearDown(self): - testing.tearDown() - - def test_my_view(self): - from myproject.views.default import my_view - request = testing.DummyRequest() - info = my_view(request) - self.assertEqual(info['project'], 'myproject') - - def test_notfound_view(self): - from myproject.views.notfound import notfound_view - request = testing.DummyRequest() - info = notfound_view(request) - self.assertEqual(info, {}) - - -class FunctionalTests(unittest.TestCase): - def setUp(self): - from myproject import main - app = main({}) - from webtest import TestApp - self.testapp = TestApp(app) - - def test_root(self): - res = self.testapp.get('/', status=200) - self.assertTrue(b'Pyramid' in res.body) - - def test_notfound(self): - res = self.testapp.get('/badurl', status=404) - self.assertTrue(res.status_code == 404) diff --git a/docs/narr/myproject/tests/test_views.py b/docs/narr/myproject/tests/test_views.py new file mode 100644 index 000000000..1fd9db8ab --- /dev/null +++ b/docs/narr/myproject/tests/test_views.py @@ -0,0 +1,13 @@ +from myproject.views.default import my_view +from myproject.views.notfound import notfound_view + + +def test_my_view(app_request): + info = my_view(app_request) + assert app_request.response.status_int == 200 + assert info['project'] == 'myproject' + +def test_notfound_view(app_request): + info = notfound_view(app_request) + assert app_request.response.status_int == 404 + assert info == {} diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 043f77754..6493f0fe7 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -210,9 +210,9 @@ Elided output from a run of this command on Unix is shown below: Running setup.py develop for myproject Successfully installed Jinja2-2.10.3 Mako-1.1.0 MarkupSafe-1.1.1 \ PasteDeploy-2.0.1 Pygments-2.5.2 hupper-1.9.1 myproject plaster-1.0 \ - plaster-pastedeploy-0.7 pyramid-1.10.4 pyramid-debugtoolbar-4.5.1 \ + plaster-pastedeploy-0.7 pyramid-1.10.4 pyramid-debugtoolbar-4.5.2 \ pyramid-jinja2-2.8 pyramid-mako-1.1.0 repoze.lru-0.7 \ - translationstring-1.3 venusian-3.0.0 waitress-1.4.1 webob-1.8.5 \ + translationstring-1.3 venusian-3.0.0 waitress-1.4.2 webob-1.8.5 \ zope.deprecation-4.4.0 zope.interface-4.7.1 This will install a :term:`distribution` representing your project into the @@ -264,9 +264,9 @@ Here's sample output from a test run on Unix: $VENV/bin/pytest -q .... - 4 passed in 0.45 seconds + 4 passed in 0.31s -The tests themselves are found in the ``test_it.py`` module in the ``tests`` package in your ``cookiecutter``-generated project. +The tests themselves are found in the ``tests`` package in your ``cookiecutter``-generated project. Within this project generated by the ``pyramid-cookiecutter-starter`` cookiecutter, only a few sample tests exist. .. note:: @@ -555,10 +555,12 @@ The ``myproject`` project we've generated has the following directory structure: │ └── notfound.py ├── production.ini ├── pytest.ini - ├── setup.py + ├── testing.ini └── tests ├── __init__.py - └── test_it.py + ├── conftest.py + ├── test_functional.py + └── test_views.py .. index:: @@ -567,17 +569,27 @@ The ``myproject`` project we've generated has the following directory structure: ``test_it.py`` ~~~~~~~~~~~~~~ -The ``test_it.py`` module in the ``tests`` package includes tests for your application. +The ``conftest.py``, ``test_functional.py``, and ``test_views.py`` modules in the ``tests`` package includes tests for your application. -.. literalinclude:: myproject/tests/test_it.py +.. literalinclude:: myproject/tests/conftest.py :language: python :linenos: -This sample ``test_it.py`` file has two unit tests and two functional tests defined within it. +.. literalinclude:: myproject/tests/test_functional.py + :language: python + :linenos: + +.. literalinclude:: myproject/tests/test_views.py + :language: python + :linenos: + +The sample ``conftest.py`` file contains test configuration and fixtures. +The sample ``test_functional.py`` file has two functional tests defined within it. +The sample ``test_views.py`` file has two unit tests defined within it. These tests are executed when you run ``pytest -q``. You may add more tests here as you build your application. You are not required to write tests to use :app:`Pyramid`. -This file is simply provided for convenience and example. +These files are provided only for convenience and example. See :ref:`testing_chapter` for more information about writing :app:`Pyramid` unit tests. @@ -615,6 +627,8 @@ describe, run, and test your application. #. ``setup.py`` is the file you'll use to test and distribute your application. It is a standard :term:`Setuptools` ``setup.py`` file. +#. ``testing.ini`` is a :term:`PasteDeploy` configuration file that can be used to execute your application's tests. + #. ``tests`` package which contains unit and functional test code for the application. .. index:: @@ -717,6 +731,19 @@ inclusion of this toolbar slows down page rendering times by over an order of magnitude. The debug toolbar is also a potential security risk if you have it configured incorrectly. + +.. index:: + single: testing.ini + +``testing.ini`` +~~~~~~~~~~~~~~~ + +The ``testing.ini`` file is a :term:`PasteDeploy` configuration file with a purpose much like that of ``development.ini``. +It is similar to ``development.ini``, but is optimized to reduce test execution time. +It disables the debug toolbar and automatic reloading of templates, as these slow down test execution. +This file is appropriate to use instead of ``development.ini`` when you run your application's tests. + + .. index:: single: MANIFEST.in diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index 0fa1e98fd..bb23d5137 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -395,23 +395,30 @@ As always, whenever you change your dependencies, make sure to run the correct $VENV/bin/pip install -e ".[testing]" -In your ``MyPackage`` project, your :term:`package` is named ``myproject`` +In your ``myproject`` project, your :term:`package` is named ``myproject`` which contains a ``views`` package containing a ``default.py`` module, which in turn contains a :term:`view` function ``my_view`` that returns an HTML body when the root URL is invoked: - .. literalinclude:: myproject/myproject/views/default.py - :linenos: - :language: python + .. literalinclude:: myproject/myproject/views/default.py + :linenos: + :language: python + +Test configuration and fixtures are defined in ``conftest.py``. +In the following example, we define a test fixture. + + .. literalinclude:: myproject/tests/conftest.py + :pyobject: testapp + :linenos: + :language: python -The following example functional tests demonstrate invoking the above :term:`view`: +This fixture is used in the following example functional tests, to demonstrate invoking the above :term:`view`: - .. literalinclude:: myproject/tests/test_it.py + .. literalinclude:: myproject/tests/test_functional.py :linenos: - :pyobject: FunctionalTests :language: python When these tests are run, each test method creates a "real" :term:`WSGI` application using the ``main`` function in your ``myproject.__init__`` module, using :term:`WebTest` to wrap that WSGI application. -It assigns the result to ``self.testapp``. +It assigns the result to ``res``. In the test named ``test_root``, the ``TestApp``'s ``GET`` method is used to invoke the root URL. An assertion is made that the returned HTML contains the text ``Pyramid``. |
