Python (unittest)测试烧瓶安全性:无法通过登录页

Python (unittest)测试烧瓶安全性:无法通过登录页,python,flask,python-unittest,flask-login,flask-security,Python,Flask,Python Unittest,Flask Login,Flask Security,我正在尝试将测试添加到我的基本应用程序中。访问所有内容都需要登录 下面是我的测试用例类: class MyAppTestCase(FlaskTestCaseMixin): def _create_app(self): raise NotImplementedError def _create_fixtures(self): self.user = EmployeeFactory() def setUp(self): s

我正在尝试将测试添加到我的基本应用程序中。访问所有内容都需要登录

下面是我的测试用例类:

class MyAppTestCase(FlaskTestCaseMixin):

    def _create_app(self):
        raise NotImplementedError

    def _create_fixtures(self):
        self.user = EmployeeFactory()

    def setUp(self):
        super(MyAppTestCase, self).setUp()
        self.app = self._create_app()
        self.client = self.app.test_client()
        self.app_context = self.app.app_context()
        self.app_context.push()
        db.create_all()
        self._create_fixtures()
        self._create_csrf_token()

    def tearDown(self):
        super(MyAppTestCase, self).tearDown()
        db.drop_all()
        self.app_context.pop()

    def _post(self, route, data=None, content_type=None, follow_redirects=True, headers=None):
        content_type = content_type or 'application/x-www-form-urlencoded'
        return self.client.post(route, data=data, follow_redirects=follow_redirects, content_type=content_type, headers=headers)

    def _login(self, email=None, password=None):
        email = email or self.user.email
        password = password or 'password'
        data = {
            'email': email,
            'password': password,
            'remember': 'y'
            }
        return self._post('/login', data=data)


class MyFrontendTestCase(MyAppTestCase):

    def _create_app(self):
        return create_app(settings)

    def setUp(self):
        super(MyFrontendTestCase, self).setUp()
        self._login()
我正在运行我的测试,在终端中使用nosetests,如下所示:
sourcemyenv/bin/activate&&nosetests--exe

这样的基本测试失败:

class CoolTestCase(MyFrontendTestCase):

    def test_logged_in(self):
        r = self._login()
        self.assertIn('MyAppName', r.data)

    def test_authenticated_access(self):
        r = self.get('/myroute/')
        self.assertIn('MyAppName', r.data)
从输出中,我看到
r.data
只是登录页面的HTML,没有错误(例如,错误的用户名或密码)或警报(“请登录以访问此页面”)

我是在
设置过程中登录的,因此
测试\u验证\u访问
应该允许我访问
/myroute/
或将我重定向到登录页面,并显示一条闪烁的消息“请登录以访问此页面”。但事实并非如此


我不知道怎么了。我根据我在Flask文档中找到的测试结果进行测试,在自杀一周后,我终于找到了答案

有几个问题:

  • Flask Security和Flask SSLify之间存在一些冲突。尽管自动https重定向在实际的web服务器上运行良好,但在测试中它完全阻止登录。我通过制作假测试路线并尝试发布随机数据来解决这个问题。测试客户端中没有
    POST
    工作。为了解决这个问题,我必须将测试配置
    DEBUG
    更改为
    True
    。请注意,这不是一个很好的解决方法,因为像CSS和JS这样的东西不会被编译,其他应用程序的行为可能会有所不同

  • Flask Security不适用于factory\u boy(或者我没有正确使用factory\u boy?)我试图通过factory\u boy创建用户和角色,因为我看到了一些使用它的示例应用程序教程。在我修复了上述问题后,它一直告诉我用户不存在。最后,我从Flask Security自己的测试中窃取了创建不同角色的假用户的代码

  • 问题代码:

    session = db.create_scoped_session()
    
    class RoleFactory(SQLAlchemyModelFactory):
        FACTORY_FOR = Role
        FACTORY_SESSION = session
    
        id = Sequence(int)
        name = 'admin'
        description = 'Administrator'
    
    
    class EmployeeFactory(SQLAlchemyModelFactory):
        FACTORY_FOR = Employee
        FACTORY_SESSION = session
    
        id = Sequence(int)
        email = Sequence(lambda n: 'user{0}@app.com'.format(n))
        password = LazyAttribute(lambda a: encrypt_password('password'))
        username = Sequence(lambda n: 'user{0}'.format(n))
        #last_login_at = datetime.utcnow()
        #current_login_at = datetime.utcnow()
        last_login_ip = '127.0.0.1'
        current_login_ip = '127.0.0.1'
        login_count = 1
        roles = LazyAttribute(lambda _: [RoleFactory()])
        active = True
    
    这是我的测试用例:

    class MyAppTestCase(FlaskTestCaseMixin, MyTestCase):
    
        def _create_app(self):
            raise NotImplementedError
    
        def _create_fixtures(self):
            #self.user = EmployeeFactory()
            populate_data(1)
    
        def setUp(self):
            super(MyAppTestCase, self).setUp()
            self.app = self._create_app()
            self.client = self.app.test_client()
            self.app_context = self.app.app_context()
            self.app_context.push()
            db.create_all()
            self._create_fixtures()
            self._create_csrf_token()
    
        def tearDown(self):
            super(MyAppTestCase, self).tearDown()
            db.drop_all()
            self.app_context.pop()
    
        def _post(self, route, data=None, content_type=None, follow_redirects=True, headers=None):
            content_type = content_type or 'application/x-www-form-urlencoded'
            return self.client.post(route, data=data, follow_redirects=follow_redirects, content_type=content_type, headers=headers)
    
        def _login(self, email=None, password=None):
            email = email or 'matt@lp.com' #self.user.email
            password = password or 'password'
            data = {
                'email': email,
                'password': password,
                'remember': 'y'
                }
            return self._post('/login', data=data)
    

    在使用Flask Security(使用Flask登录)应用程序的测试中,我的登录/注销也有问题。我通过模拟
    flask\u login.\u get\u user
    函数并将
    app.login\u manager.\u login\u disabled
    设置为True,解决了这个问题

    模拟用户的上下文管理器:

    class LoginLogoutMixin(object):
        @contextmanager
        def login(self, user):
            mock_get_user = patch('flask_login._get_user', Mock(return_value=user))
            self.app.login_manager._login_disabled = True
            mock_get_user.start()
            yield
            mock_get_user.stop()
            self.app.login_manager._login_disabled = False
    
    以及它的用法示例:

    class ProtectedViewTestCase(LoginLogoutMixin, TestCase):
    
        def setUp(self):
            super(ProtectedViewTestCase, self).setUp()
            # create user here
    
        def test_protected_view(self):
            with self.login(self.user):
                rv = self.client.get(url_for('protected_view'))
                self.assert200(rv)
    

    我看到你在使用CSRF代币——你是否尝试过禁用它们,看看这是否能让你走得更远?我知道他们在测试中咬我的次数比我记忆中的要多。如果你正在使用(或可以使用)Flask 0.10,我强烈建议你只使用新的假上下文内容:我们目前正在做一些非常类似于你在测试中所做的事情,一旦我们可以升级,为了这个,我把一切都扯了出来。@RachelSanders-我已经启用了
    WTF\u CSRF\u
    设置为
    False
    @RachelSanders-我只是尝试使用假上下文和Flask登录功能
    Login\u user
    。现在,它显示了一条闪现的消息“您没有查看此资源的权限”。因此发生了一些更改,但登录仍然不起作用。您描述的行为符合@RachelSanders提到的CSRF问题。确保您的
    create_app()
    正在使用您的测试配置。或者打印
    app.config['WTF\u CSRF\u ENABLED']
    以确保此设置在应用程序中处于活动状态。您列出了问题测试,但没有列出工作测试。在这里不容易找到它。