单元测试烧瓶主体应用程序 [英] Unit-testing a flask-principal application

查看:114
本文介绍了单元测试烧瓶主体应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所有,我正在写一个瓶颈应用程序,依靠 flask-principal 来管理用户角色。我想写一些简单的单元测试来检查哪些用户可以访问哪些视图。代码的一个例子是在pastebin 上发布,以避免混乱这篇文章。简而言之,我定义了一些路线,装饰一些只能由具有适当角色的用户访问,然后尝试在测试中访问它们。



在代码粘贴, test_member test_admin_b 都失败,抱怨 PermissionDenied 。显然,我没有正确地声明用户。至少,有关用户角色的信息不在正确的上下文中。



任何有关上下文处理复杂性的帮助或洞察都将深表赞赏。

解决方案

Flask-Principal不会为您在请求之间存储信息。无论你喜欢做什么,都由你来决定。记住这一点,并考虑一下你的测试。您可以在 setUpClass 方法中调用 test_request_context 方法。这创建了一个新的请求上下文。您还在测试中使用 self.client.get(..)进行测试客户端调用。这些调用创建了另一个不相互共享的请求上下文。因此,您对 identity_changed.send(..)的调用不会在检查权限的请求的上下文中发生。我已经提前编辑你的代码,使测试通过,希望它能帮助你理解。请特别注意在 create_app 方法中添加的 before_request 过滤器。

 导入hmac 
导入单元测试
$ b $ from functools导入包装
从hashlib导入sha1

导入烧瓶
$ b $ from flask.ext.principal import委托人,权限,角色需求,身份,\
identity_changed,identity_loaded current_app

$ b def roles_required( *角色):
装饰者,指定用户必须具有所有指定的角色。
示例::

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

当前用户必须同时拥有admin角色和`editor`角色以
的顺序来查看页面

:param args:所需的角色

来源:https://github.com/ mattupstate / flask-security /

def wra pper(fn):
@wraps(fn)
def deco_view(* args,** kwargs):
perms = [角色中的角色权限(RoleNeed(角色)] $ b perm.can():
#return _get_unauthorized_view()
flask.abort(403)
返回fn(* args,** kwargs)
return decorated_view
返回包装


$ b def roles_accepted(* roles):
Decorator指定用户必须至少有一个
指定的角色。示例::

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

当前用户必须在
中具有`editor`或`author`角色才能查看页面。

:param args:可能的角色。
def包装(fn):
@wraps(fn)
def deco_view(* args,** kwargs):
perm =权限(* [角色角色角色])
如果perm.can():
返回fn(* args,** kwargs)
flask.abort(403)
返回decorated_view
返回包装


def _on_principal_init(发件人,身份):
如果identity.id =='admin':
identity.provides。添加(RoleNeed('admin'))
identity.provides.add(RoleNeed('member'))

$ b $ 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():
#这是获取用户认证信息的地方,可以完成
#例如,你可以将用户信息存储在
#session中,或者在HTTP标头,查询字符串等等中查找认证
#...
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():
返回OK

@ app.route('/ admin_b')
@ admin_permission.require()
def connect_admin_alt():
返回OK

返回应用程序


admin_permission =权限(RoleNeed('admin'))


类WorkshopTest(unittest.TestCase):

@classmethod
de f setUpClass(cls):
app = create_app()
cls.app = app
cls.client = app.test_client()
$ b $ 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()


All, I'm writing a flask application that depends on flask-principal for managing user roles. I'd like to write some simple unit tests to check which views can be accessed by which user. An example of code is posted on pastebin to avoid cluttering this post. In short, I define a few routes, decorating some so that they can be accessed only by users with the proper role, then try to access them in a test.

In the code pasted, the test_member and test_admin_b both fail, complaining about a PermissionDenied. Obviously, I'm failing to declare the user properly; at least, the info about the user roles is not in the right context.

Any help or insight about the complexities of context processing will be deeply appreciated.

解决方案

Flask-Principal does not store information for you between requests. It's up to you to do this however you like. Keep that in mind and think about your tests for a moment. You call the test_request_context method in the setUpClass method. This creates a new request context. You are also making test client calls with self.client.get(..) in your tests. These calls create additional request contexts that are not shared between each other. Thus, your calls to identity_changed.send(..) do not happen with the context of the requests that are checking for permissions. I've gone ahead and edited your code to make the tests pass in hopes that it will help you understand. Pay special attention to the before_request filter I added in the create_app method.

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()

这篇关于单元测试烧瓶主体应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆