在烧瓶测试请求上下文中触发多个请求

时间:2017-08-22 15:04:39

标签: python flask

我目前正在为烧瓶应用编写单元测试,这需要在测试期间保持打开会话。为此,我发现我可以使用test_request_context。这工作正常,直到我需要发出多个请求。

我当前的测试涉及登录/注销系统,我需要确保在用户单击注销按钮时实际从会话中重置某些属性。

我的代码的一个粗略示例:

from unittest import TestCase
from flask import Flask, session
from mypackage import auth_blueprint


class FlaskTestCase(TestCase):
    def setUp(self):
        self.app = Flask(__name__)
        self.app.secret_key = urandom(24)
        self.app.register_blueprint(auth_blueprint)   # The blueprint to test
        self.client = self.app.test_client()

    def test_login_logout():
        with self.app.test_request_context("/auth/login", data={"username": "foo", "password": "bar"}, method="POST"):
            assert session["logged_in"]
            # How would I make A call to logout?
            # self.client.post("/auth/logout") doesn't work
            assert not session["logged_in"]

有谁知道如何在一次测试中进行多次通话并检查同一个会话?感谢您的帮助

2 个答案:

答案 0 :(得分:1)

您应该能够为两个呼叫使用相同的上下文。我用flask_restful尝试了这个并且它有效。您可以阅读应用程序上下文以及它们的传递方式。此外,您可以尝试使用current_app上下文:

from flask import current_app
current_app.app_context()

我先试试这个:

from unittest import TestCase
from flask import Flask, session
from mypackage import auth_blueprint


class FlaskTestCase(TestCase):
    def setUp(self):
        self.app = Flask(__name__)
        self.app.secret_key = urandom(24)
        self.app.register_blueprint(auth_blueprint)   # The blueprint to test
        self.client = self.app.test_client()
        self.app.app_context().push()


    def test_login_logout():
        with self.app.app_context():
            self.client.post("/auth/login", data={"username": "foo", "password": "bar"})
            assert session["logged_in"]
            # How would I make A call to logout?
            self.client.post("/auth/logout")
            assert not session["logged_in"]

答案 1 :(得分:0)

您可以使用setUpClass和tearDownClass。首先,您需要定义一个在单独的测试文件中调用的全局TestCase。

我给出的示例是使用connexion。您可以通过更新setUpClass定义并仅将该应用程序定义为Flask应用程序来进行调整。

test_server.py

import unittest
import os
import connexion
import logbook

from config import db
from models import Book


# Logging configuration
log = logbook.Logger(__name__)

# Books Fixtures
BOOKS = [
    {
        'name': 'Book 1',
    },
    {
        'name': 'Book 2',
    },
    {
        'name': 'Book 3'
    },
]


class TestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        basedir = os.path.abspath(os.path.dirname(__file__))
        log.info("setUpClass")
        # Setting UP the DB and the tests
        cls.connex_app = connexion.App(__name__, specification_dir=basedir)
        cls.connex_app.add_api('swagger.yml', validate_responses=True)
        cls.connex_app.app.config['TESTING'] = True
        cls.connex_app.app.config['WTF_CSRF_ENABLED'] = False
        cls.connex_app.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'test.db')
        # Delete DB if exists : not for production
        if os.path.exists('test.db'):
            os.remove('test.db')
        db.create_all()
        TestCase.add_sample_algorithm()
        TestCase.add_sample_backtest()
        cls.test_client = cls.connex_app.app.test_client()

    @staticmethod
    def add_sample_book():
        # Iterate over the BOOKS Dictionary and populate the DB :
        for book in BOOKS:
            book_to_add = Book(name=book['name'])
            log.info("## Book to add:" + str(book_to_add))
            db.session.add(book_to_add)

        db.session.commit()

    @classmethod
    def tearDownClass(cls):
        log.info("tearDownClass ")
        db.session.remove()
        db.drop_all()
        if os.path.exists('test.db'):
            os.remove('test.db')


if __name__ == '__main__':
    unittest.main()

然后,您可以在每个测试文件中调用测试服务器,该服务器将创建测试数据库,运行测试客户端,然后在完成一系列测试后将其拆解。以这种方式定义的setUpClass和tearDownClass可以避免出现问题(从多个测试文件调用测试服务器时出现蓝图(例如attributeError:蓝图之间发生名称冲突)。

from test_server import TestCase


class BookTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super(BookTest, cls).setUpClass()
        # Additional initialization

    @classmethod
    def tearDownClass(cls):
        super(BookTest, cls).tearDownClass()

    def test_get_root(self):
        resp = self.test_client.get('/')
        self.assertEqual(404, resp.status_code)

    def test_get_all_books(self):
        resp = self.test_client.get('/api/books')
        self.assertEqual(200, resp.status_code)
        self.assertEqual(3, len(resp.json))

        # Book 1 :
        self.assertEqual(resp.json[0]['name'], "Book 1")

谢谢

阿尤布

相关问题