summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Zwerschke <cito@online.de>2011-06-05 17:29:52 +0200
committerChristoph Zwerschke <cito@online.de>2011-06-05 17:29:52 +0200
commit487f7e763935caf4ff9f2b6518512b9e915fe2c2 (patch)
tree829f38988bc8d35a5406e3d2281cac22a7713e94
parent879bb56558527e402bc8b0135ce2b40d24fe4a12 (diff)
downloadpyramid-487f7e763935caf4ff9f2b6518512b9e915fe2c2.tar.gz
pyramid-487f7e763935caf4ff9f2b6518512b9e915fe2c2.tar.bz2
pyramid-487f7e763935caf4ff9f2b6518512b9e915fe2c2.zip
Make tests in the Wiki2 tutorial a separate chapter, as for Wiki1.
Also add functional tests to the Wiki2 tutorial, similar to Wiki1.
-rw-r--r--docs/tutorials/wiki2/definingviews.rst43
-rw-r--r--docs/tutorials/wiki2/index.rst1
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/models.py3
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/views.py8
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/models.py3
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/tests.py267
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/models.py1
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/views.py8
-rw-r--r--docs/tutorials/wiki2/tests.rst74
9 files changed, 357 insertions, 51 deletions
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index 8fd9a9399..cea376b77 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -341,46 +341,3 @@ Exception('Forced Exception')``). Then visit the error-raising view
in a browser. You should see an interactive exception handler in the
browser which allows you to examine values in a post-mortem mode.
-Adding Tests
-============
-
-Since we've added a good bit of imperative code here, it's useful to
-define tests for the views we've created. We'll change our tests.py
-module to look like this:
-
-.. literalinclude:: src/views/tutorial/tests.py
- :linenos:
- :language: python
-
-We can then run the tests using something like:
-
-.. code-block:: text
- :linenos:
-
- $ python setup.py test -q
-
-The expected output is something like:
-
-.. code-block:: text
- :linenos:
-
- running test
- running egg_info
- writing requirements to tutorial.egg-info/requires.txt
- writing tutorial.egg-info/PKG-INFO
- writing top-level names to tutorial.egg-info/top_level.txt
- writing dependency_links to tutorial.egg-info/dependency_links.txt
- writing entry points to tutorial.egg-info/entry_points.txt
- unrecognized .svn/entries format in
- reading manifest file 'tutorial.egg-info/SOURCES.txt'
- writing manifest file 'tutorial.egg-info/SOURCES.txt'
- running build_ext
- ......
- ----------------------------------------------------------------------
- Ran 6 tests in 0.181s
-
- OK
-
-
-
-
diff --git a/docs/tutorials/wiki2/index.rst b/docs/tutorials/wiki2/index.rst
index b8bc9b4cb..d05d70f3c 100644
--- a/docs/tutorials/wiki2/index.rst
+++ b/docs/tutorials/wiki2/index.rst
@@ -23,6 +23,7 @@ tutorial can be browsed at
definingmodels
definingviews
authorization
+ tests
distributing
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models.py b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
index 422728383..53c6d1122 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
@@ -34,8 +34,9 @@ def initialize_sql(engine):
Base.metadata.bind = engine
Base.metadata.create_all(engine)
try:
+ transaction.begin()
session = DBSession()
- page = Page('FrontPage', 'initial data')
+ page = Page('FrontPage', 'This is the front page')
session.add(page)
transaction.commit()
except IntegrityError:
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views.py b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
index 5abd8391e..e0b84971d 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
@@ -2,7 +2,7 @@ import re
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound
+from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from pyramid.security import authenticated_userid
from pyramid.url import route_url
@@ -19,7 +19,9 @@ def view_wiki(request):
def view_page(request):
pagename = request.matchdict['pagename']
session = DBSession()
- page = session.query(Page).filter_by(name=pagename).one()
+ page = session.query(Page).filter_by(name=pagename).first()
+ if page is None:
+ return HTTPNotFound('No such page')
def check(match):
word = match.group(1)
@@ -51,7 +53,7 @@ def add_page(request):
page = Page('', '')
logged_in = authenticated_userid(request)
return dict(page=page, save_url=save_url, logged_in=logged_in)
-
+
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
diff --git a/docs/tutorials/wiki2/src/models/tutorial/models.py b/docs/tutorials/wiki2/src/models/tutorial/models.py
index 096b884d9..ecc8d567b 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/models.py
@@ -32,8 +32,9 @@ def initialize_sql(engine):
Base.metadata.bind = engine
Base.metadata.create_all(engine)
try:
+ transaction.begin()
session = DBSession()
- page = Page('FrontPage', 'initial data')
+ page = Page('FrontPage', 'This is the front page')
session.add(page)
transaction.commit()
except IntegrityError:
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests.py b/docs/tutorials/wiki2/src/tests/tutorial/tests.py
new file mode 100644
index 000000000..bb75efeb5
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/tests.py
@@ -0,0 +1,267 @@
+import unittest
+
+from pyramid import testing
+
+
+def _initTestingDB():
+ from tutorial.models import DBSession
+ from tutorial.models import Base
+ from sqlalchemy import create_engine
+ engine = create_engine('sqlite:///:memory:')
+ DBSession.configure(bind=engine)
+ Base.metadata.bind = engine
+ Base.metadata.create_all(engine)
+ return DBSession
+
+def _registerRoutes(config):
+ config.add_route('view_page', '{pagename}')
+ config.add_route('edit_page', '{pagename}/edit_page')
+ config.add_route('add_page', 'add_page/{pagename}')
+
+
+class PageModelTests(unittest.TestCase):
+
+ def setUp(self):
+ self.session = _initTestingDB()
+
+ def tearDown(self):
+ self.session.remove()
+
+ def _getTargetClass(self):
+ from tutorial.models import Page
+ return Page
+
+ def _makeOne(self, name='SomeName', data='some data'):
+ return self._getTargetClass()(name, data)
+
+ def test_constructor(self):
+ instance = self._makeOne()
+ self.assertEqual(instance.name, 'SomeName')
+ self.assertEqual(instance.data, 'some data')
+
+class InitializeSqlTests(unittest.TestCase):
+
+ def setUp(self):
+ from tutorial.models import DBSession
+ DBSession.remove()
+
+ def tearDown(self):
+ from tutorial.models import DBSession
+ DBSession.remove()
+
+ def _callFUT(self, engine):
+ from tutorial.models import initialize_sql
+ return initialize_sql(engine)
+
+ def test_it(self):
+ from sqlalchemy import create_engine
+ engine = create_engine('sqlite:///:memory:')
+ self._callFUT(engine)
+ from tutorial.models import DBSession, Page
+ self.assertEqual(DBSession.query(Page).one().data,
+ 'This is the front page')
+
+class ViewWikiTests(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from tutorial.views import view_wiki
+ return view_wiki(request)
+
+ def test_it(self):
+ _registerRoutes(self.config)
+ request = testing.DummyRequest()
+ response = self._callFUT(request)
+ self.assertEqual(response.location, 'http://example.com/FrontPage')
+
+class ViewPageTests(unittest.TestCase):
+ def setUp(self):
+ self.session = _initTestingDB()
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ self.session.remove()
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from tutorial.views import view_page
+ return view_page(request)
+
+ def test_it(self):
+ from tutorial.models import Page
+ request = testing.DummyRequest()
+ request.matchdict['pagename'] = 'IDoExist'
+ page = Page('IDoExist', 'Hello CruelWorld IDoExist')
+ self.session.add(page)
+ _registerRoutes(self.config)
+ info = self._callFUT(request)
+ self.assertEqual(info['page'], page)
+ self.assertEqual(
+ info['content'],
+ '<div class="document">\n'
+ '<p>Hello <a href="http://example.com/add_page/CruelWorld">'
+ 'CruelWorld</a> '
+ '<a href="http://example.com/IDoExist">'
+ 'IDoExist</a>'
+ '</p>\n</div>\n')
+ self.assertEqual(info['edit_url'],
+ 'http://example.com/IDoExist/edit_page')
+
+class AddPageTests(unittest.TestCase):
+ def setUp(self):
+ self.session = _initTestingDB()
+ self.config = testing.setUp()
+ self.config.begin()
+
+ def tearDown(self):
+ self.session.remove()
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from tutorial.views import add_page
+ return add_page(request)
+
+ def test_it_notsubmitted(self):
+ _registerRoutes(self.config)
+ request = testing.DummyRequest()
+ request.matchdict = {'pagename':'AnotherPage'}
+ info = self._callFUT(request)
+ self.assertEqual(info['page'].data,'')
+ self.assertEqual(info['save_url'],
+ 'http://example.com/add_page/AnotherPage')
+
+ def test_it_submitted(self):
+ from tutorial.models import Page
+ _registerRoutes(self.config)
+ request = testing.DummyRequest({'form.submitted':True,
+ 'body':'Hello yo!'})
+ request.matchdict = {'pagename':'AnotherPage'}
+ self._callFUT(request)
+ page = self.session.query(Page).filter_by(name='AnotherPage').one()
+ self.assertEqual(page.data, 'Hello yo!')
+
+class EditPageTests(unittest.TestCase):
+ def setUp(self):
+ self.session = _initTestingDB()
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ self.session.remove()
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from tutorial.views import edit_page
+ return edit_page(request)
+
+ def test_it_notsubmitted(self):
+ from tutorial.models import Page
+ _registerRoutes(self.config)
+ request = testing.DummyRequest()
+ request.matchdict = {'pagename':'abc'}
+ page = Page('abc', 'hello')
+ self.session.add(page)
+ info = self._callFUT(request)
+ self.assertEqual(info['page'], page)
+ self.assertEqual(info['save_url'],
+ 'http://example.com/abc/edit_page')
+
+ def test_it_submitted(self):
+ from tutorial.models import Page
+ _registerRoutes(self.config)
+ request = testing.DummyRequest({'form.submitted':True,
+ 'body':'Hello yo!'})
+ request.matchdict = {'pagename':'abc'}
+ page = Page('abc', 'hello')
+ self.session.add(page)
+ response = self._callFUT(request)
+ self.assertEqual(response.location, 'http://example.com/abc')
+ self.assertEqual(page.data, 'Hello yo!')
+
+class FunctionalTests(unittest.TestCase):
+
+ viewer_login = '/login?login=viewer&password=viewer' \
+ '&came_from=FrontPage&form.submitted=Login'
+ viewer_wrong_login = '/login?login=viewer&password=incorrect' \
+ '&came_from=FrontPage&form.submitted=Login'
+ editor_login = '/login?login=editor&password=editor' \
+ '&came_from=FrontPage&form.submitted=Login'
+
+ def setUp(self):
+ from tutorial import main
+ settings = { 'sqlalchemy.url': 'sqlite:///:memory:'}
+ app = main({}, **settings)
+ from webtest import TestApp
+ self.testapp = TestApp(app)
+
+ def tearDown(self):
+ del self.testapp
+ from tutorial.models import DBSession
+ DBSession.remove()
+
+ def test_root(self):
+ res = self.testapp.get('/', status=302)
+ self.assertTrue(not res.body)
+
+ def test_FrontPage(self):
+ res = self.testapp.get('/FrontPage', status=200)
+ self.assertTrue('FrontPage' in res.body)
+
+ def test_unexisting_page(self):
+ res = self.testapp.get('/SomePage', status=404)
+ self.assertTrue('No such page' in res.body, res.body)
+
+ def test_successful_log_in(self):
+ res = self.testapp.get(self.viewer_login, status=302)
+ self.assertTrue(res.location == 'FrontPage')
+
+ def test_failed_log_in(self):
+ res = self.testapp.get(self.viewer_wrong_login, status=200)
+ self.assertTrue('login' in res.body)
+
+ def test_logout_link_present_when_logged_in(self):
+ self.testapp.get(self.viewer_login, status=302)
+ res = self.testapp.get('/FrontPage', status=200)
+ self.assertTrue('Logout' in res.body)
+
+ def test_logout_link_not_present_after_logged_out(self):
+ self.testapp.get(self.viewer_login, status=302)
+ self.testapp.get('/FrontPage', status=200)
+ res = self.testapp.get('/logout', status=302)
+ self.assertTrue('Logout' not in res.body)
+
+ def test_anonymous_user_cannot_edit(self):
+ res = self.testapp.get('/FrontPage/edit_page', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_anonymous_user_cannot_add(self):
+ res = self.testapp.get('/add_page/NewPage', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_viewer_user_cannot_edit(self):
+ self.testapp.get(self.viewer_login, status=302)
+ res = self.testapp.get('/FrontPage/edit_page', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_viewer_user_cannot_add(self):
+ self.testapp.get(self.viewer_login, status=302)
+ res = self.testapp.get('/add_page/NewPage', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_editors_member_user_can_edit(self):
+ self.testapp.get(self.editor_login, status=302)
+ res = self.testapp.get('/FrontPage/edit_page', status=200)
+ self.assertTrue('Editing' in res.body)
+
+ def test_editors_member_user_can_add(self):
+ self.testapp.get(self.editor_login, status=302)
+ res = self.testapp.get('/add_page/NewPage', status=200)
+ self.assertTrue('Editing' in res.body)
+
+ def test_editors_member_user_can_view(self):
+ self.testapp.get(self.editor_login, status=302)
+ res = self.testapp.get('/FrontPage', status=200)
+ self.assertTrue('FrontPage' in res.body)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/models.py b/docs/tutorials/wiki2/src/views/tutorial/models.py
index 11e91232e..960c14941 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/models.py
@@ -31,6 +31,7 @@ def initialize_sql(engine):
Base.metadata.bind = engine
Base.metadata.create_all(engine)
try:
+ transaction.begin()
session = DBSession()
page = Page('FrontPage', 'initial data')
session.add(page)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/views.py b/docs/tutorials/wiki2/src/views/tutorial/views.py
index b8896abe7..57c1865b5 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/views.py
@@ -2,7 +2,7 @@ import re
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound
+from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from pyramid.url import route_url
from tutorial.models import DBSession
@@ -18,7 +18,9 @@ def view_wiki(request):
def view_page(request):
matchdict = request.matchdict
session = DBSession()
- page = session.query(Page).filter_by(name=matchdict['pagename']).one()
+ page = session.query(Page).filter_by(name=pagename).first()
+ if page is None:
+ return HTTPNotFound('No such page')
def check(match):
word = match.group(1)
@@ -48,7 +50,7 @@ def add_page(request):
save_url = route_url('add_page', request, pagename=name)
page = Page('', '')
return dict(page=page, save_url=save_url)
-
+
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
diff --git a/docs/tutorials/wiki2/tests.rst b/docs/tutorials/wiki2/tests.rst
new file mode 100644
index 000000000..7a4e65529
--- /dev/null
+++ b/docs/tutorials/wiki2/tests.rst
@@ -0,0 +1,74 @@
+============
+Adding Tests
+============
+
+We will now add tests for the models and the views and a few functional
+tests in the ``tests.py``. Tests ensure that an application works, and
+that it continues to work after some changes are made in the future.
+
+Testing the Models
+==================
+
+We write a test class for the model class ``Page`` and another test class
+for the ``initialize_sql`` function.
+
+To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a
+result of the ``pyramid_routesalchemy`` project generator. We'll add two
+test classes: one for the ``Page`` model named ``PageModelTests``, one for the
+``initialize_sql`` function named ``InitializeSqlTests``.
+
+Testing the Views
+=================
+
+We'll modify our ``tests.py`` file, adding tests for each view function we
+added above. As a result, we'll *delete* the ``ViewTests`` test in the file,
+and add four other test classes: ``ViewWikiTests``, ``ViewPageTests``,
+``AddPageTests``, and ``EditPageTests``. These test the ``view_wiki``,
+``view_page``, ``add_page``, and ``edit_page`` views respectively.
+
+Functional tests
+================
+
+We test the whole application, covering security aspects that are not
+tested in the unit tests, like logging in, logging out, checking that
+the ``viewer`` user cannot add or edit pages, but the ``editor`` user
+can, and so on.
+
+Viewing the results of all our edits to ``tests.py``
+====================================================
+
+Once we're done with the ``tests.py`` module, it will look a lot like the
+below:
+
+.. literalinclude:: src/tests/tutorial/tests.py
+ :linenos:
+ :language: python
+
+Running the Tests
+=================
+
+We can run these tests by using ``setup.py test`` in the same way we did in
+:ref:`running_tests`. Assuming our shell's current working directory is the
+"tutorial" distribution directory:
+
+On UNIX:
+
+.. code-block:: text
+
+ $ ../bin/python setup.py test -q
+
+On Windows:
+
+.. code-block:: text
+
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
+
+The expected result looks something like:
+
+.. code-block:: text
+
+ ......................
+ ----------------------------------------------------------------------
+ Ran 22 tests in 2.700s
+
+ OK