Test utilities for repoze.who
-powered applications¶
Author: | Gustavo Narea. |
---|---|
Latest release: | 1.0.1 |
Overview
repoze.who-testutil is a repoze.who
plugin which modifies
repoze.who
‘s original middleware to make it easier to forge
authentication, without bypassing identification (this is, running the
metadata providers).
It’s been created in order to ease testing of repoze.who
-powered
applications, in a way independent of the identifiers, authenticators
and challengers used originally by your application, so that you won’t
have to update your test suite as your application grows and the
authentication method changes.
The problems¶
While testing protected areas, you have to authenticate first¶
And that’s absolutely specific to the identifiers/challengers you’re using.
For example, if you’re using WebTest and
the repoze.who.plugins.form.RedirectingFormPlugin
plugin, you have to
get the login handler at the beginning of each test that covers situations
where the user is authenticated:
class TestControlPanel(TestCase):
def setUp(self):
from paste.deploy import loadapp
from webtest import TestApp
wsgiapp = loadapp('config:test.ini')
self.app = TestApp(wsgiapp)
def test_index_as_admin(self):
# First of all, let's log in the RedirectingFormPlugin way:
self.app.get('/login_handler?login=admin&password=somepass')
# Now that we're authenticated, let's request the control panel:
resp = self.app.get('/panel/', status=200)
assert "some text" in resp.body
def test_index_as_normal_user(self):
# First of all, let's log in the RedirectingFormPlugin way:
self.app.get('/login_handler?login=foo&password=bar')
# Now that we're authenticated, let's request the control panel:
self.app.get('/panel/', status=302)
# We got a 302 redirection. This is the RedirectingFormPlugin way
# to let us know that authorization was denied.
def test_index_as_anonymous(self):
# Let's request the control panel as an anonymous user:
self.app.get('/panel/', status=302)
# We got a 302 redirection. This is the RedirectingFormPlugin way
# to let us know that authorization was denied.
This is, we end up testing protected areas in a way that is totally tied to
the repoze.who
identifiers and challengers you intend to use initially.
If the are replaced later, you will have to update many of your tests (most
of them, possibly).
Or, while testing protected areas, you have to forge authentication¶
But that will bypass identification: The metadata providers won’t get run, so this is not an option if your application relies on them:
class TestControlPanel(TestCase):
def setUp(self):
from paste.deploy import loadapp
from webtest import TestApp
wsgiapp = loadapp('config:test.ini')
self.app = TestApp(wsgiapp)
def test_index_as_admin(self):
# Let's forge authentication:
environ = {'REMOTE_USER': 'admin'}
resp = self.app.get('/panel/', extra_environ=environ, status=200)
assert "some text" in resp.body
This seems like the best way to test a protected area, and you may expect it to work, but unfortunately it won’t:
If the controller action for '/panel/'
assumes that if the user is
authenticated, her full name will be available in
identity['full_name']
, then your test will be broken because such an item
won’t be defined in the identity
dict – even worse: the identity
dict
won’t even be defined because repoze.who
will assume that, because
environ['REMOTE_USER']
is set, it won’t be necessary to run its middleware.
The solution¶
It’s absolutely unnecessary to test authentication every time you test a protected area in your Web site; authentication should be tested once and separately. This is, to test a protected area in a Web site, only identification and authorization are required, not authentication.
With repoze.who-testutil, you’ll be able to write tests for protected areas the way you’d expect:
class TestControlPanel(TestCase):
def setUp(self):
from paste.deploy import loadapp
from webtest import TestApp
wsgiapp = loadapp('config:test.ini')
self.app = TestApp(wsgiapp)
def test_index_as_admin(self):
environ = {'REMOTE_USER': 'admin'}
resp = self.app.get('/panel/', extra_environ=environ, status=200)
assert "some text" in resp.body
def test_index_as_normal_user(self):
environ = {'REMOTE_USER': 'foobar'}
# The 403 HTTP status code means that authorization has been
# denied, while we are aware of who the user is:
self.app.get('/panel/', status=403)
def test_index_as_anonymous(self):
# Let's request the control panel as an anonymous user.
# The 401 HTTP status code means that authorization has been
# denied, although it may be granted if the user logs in:
self.app.get('/panel/', extra_environ=environ, status=401)
As you may have noticed, these tests are absolutely independent of the
repoze.who
plugins used. And the best of all: The repoze.who
middleware won’t be skipped, so the identity
dict will be defined as usual!
Then if you want to test authentication, you can do it once and separately – and if the authentication method changes over time, you’d just have to update a few tests, instead of all the tests that cover protected areas.
How to install¶
It requires repoze.who
only, and you can install them with
easy_install
:
easy_install repoze.who-testutil
Documentation¶
Support and development¶
The prefered place to ask questions is the Repoze mailing list or the #repoze IRC channel. Bugs reports and feature requests should be sent to the issue tracker of the Repoze project.
The development mainline is available at the following Subversion repository:
http://svn.repoze.org/whoplugins/whotestutil/trunk/