对烧瓶主要应用进行单元测试

Pie*_* GM 6 python unit-testing flask flask-principal

全部,我正在编写一个烧瓶应用程序,它依赖于flask-principal来管理用户角色.我想编写一些简单的单元测试来检查哪些用户可以访问哪些视图.在pastebin上发布一个代码示例,以避免混乱这篇文章.简而言之,我定义了一些路由,修改了一些路径,以便只有具有适当角色的用户才能访问它们,然后尝试在测试中访问它们.

在粘贴的代码中,test_member并且test_admin_b两者都失败了,抱怨一个PermissionDenied.显然,我没有正确宣布用户; 至少,有关用户角色的信息不在正确的上下文中.

任何有关上下文处理复杂性的帮助或见解都将深受赞赏.

Mat*_*t W 8

Flask-Principal不会在请求之间存储信息.你喜欢这样做取决于你.记住这一点并考虑一下您的测试.您可以在test_request_context方法中调用该setUpClass方法.这将创建一个新的请求上下文.您还在测试中进行测试客户端调用self.client.get(..).这些调用会创建彼此之间不共享的其他请求上下文.因此,您的调用identity_changed.send(..)不会发生在检查权限的请求的上下文中.我已经开始编辑你的代码以使测试通过,希望它能帮助你理解.请特别注意before_request我在create_app方法中添加的过滤器.

import hmac
import unittest

from functools import wraps
from hashlib import sha1

import flask

from flask.ext.principal import Principal, Permission, RoleNeed, Identity, \
    identity_changed, identity_loaded current_app


def roles_required(*roles):
    """Decorator which specifies that a user must have all the specified roles.
    Example::

        @app.route('/dashboard')
        @roles_required('admin', 'editor')
        def dashboard():
            return 'Dashboard'

    The current user must have both the `admin` role and `editor` role in order
    to view the page.

    :param args: The required roles.

    Source: https://github.com/mattupstate/flask-security/
    """
    def wrapper(fn):
        @wraps(fn)
        def decorated_view(*args, **kwargs):
            perms = [Permission(RoleNeed(role)) for role in roles]
            for perm in perms:
                if not perm.can():
                    # return _get_unauthorized_view()
                    flask.abort(403)
            return fn(*args, **kwargs)
        return decorated_view
    return wrapper



def roles_accepted(*roles):
    """Decorator which specifies that a user must have at least one of the
    specified roles. Example::

        @app.route('/create_post')
        @roles_accepted('editor', 'author')
        def create_post():
            return 'Create Post'

    The current user must have either the `editor` role or `author` role in
    order to view the page.

    :param args: The possible roles.
    """
    def wrapper(fn):
        @wraps(fn)
        def decorated_view(*args, **kwargs):
            perm = Permission(*[RoleNeed(role) for role in roles])
            if perm.can():
                return fn(*args, **kwargs)
            flask.abort(403)
        return decorated_view
    return wrapper


def _on_principal_init(sender, identity):
    if identity.id == 'admin':
        identity.provides.add(RoleNeed('admin'))
    identity.provides.add(RoleNeed('member'))


def create_app():
    app = flask.Flask(__name__)
    app.debug = True
    app.config.update(SECRET_KEY='secret', TESTING=True)
    principal = Principal(app)
    identity_loaded.connect(_on_principal_init)

    @app.before_request
    def determine_identity():
        # This is where you get your user authentication information. This can
        # be done many ways. For instance, you can store user information in the
        # session from previous login mechanism, or look for authentication
        # details in HTTP headers, the querystring, etc...
        identity_changed.send(current_app._get_current_object(), identity=Identity('admin'))

    @app.route('/')
    def index():
        return "OK"

    @app.route('/member')
    @roles_accepted('admin', 'member')
    def role_needed():
        return "OK"

    @app.route('/admin')
    @roles_required('admin')
    def connect_admin():
        return "OK"

    @app.route('/admin_b')
    @admin_permission.require()
    def connect_admin_alt():
        return "OK"

    return app


admin_permission = Permission(RoleNeed('admin'))


class WorkshopTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        app = create_app()
        cls.app = app
        cls.client = app.test_client()

    def test_basic(self):
        r = self.client.get('/')
        self.assertEqual(r.data, "OK")

    def test_member(self):
        r = self.client.get('/member')
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.data, "OK")

    def test_admin_b(self):
        r = self.client.get('/admin_b')
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.data, "OK")


if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)