返回介绍

单元测试的改进

发布于 2025-01-02 21:53:56 字数 2770 浏览 0 评论 0 收藏 0

正如我在本章开头所暗示的,到目前为止,我所做的很多工作都是为了改进单元测试工作流程。 在运行单元测试时,要确保应用的配置方式不会污染开发资源(如数据库)。

tests.py 的当前版本采用了应用实例化之后修改配置的技巧,这是一种危险的做法,因为并不是所有类型的更改都会在修改之后才生效。 我想要的是有机会在添加到应用之前指定我想要的测试配置项。

create_app() 函数现在接受一个配置类作为参数。 默认情况下,使用在 config.py 中定义的 Config 类,但现在我可以通过将新类传递给工厂函数来创建使用不同配置的应用实例。 下面是一个适用于我的单元测试的示例配置类:

tests.py :测试配置。

from config import Config

class TestConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = 'sqlite://'

我在这里做的是创建应用的 Config 类的子类,并覆盖 SQLAlchemy 配置以使用内存 SQLite 数据库。 我还添加了一个 TESTING 属性,并设置为 True ,我目前不需要该属性,但如果应用需要确定它是否在单元测试下运行,它就派上用场了。

你一定还记得,我的单元测试依赖于 setUp()tearDown() 方法,它们由单元测试框架自动调用,以创建和销毁每次测试运行的环境。 我现在可以使用这两种方法为每个测试创建和销毁一个测试专用的应用:

tests.py :为每次测试创建一个应用。

class UserModelCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app(TestConfig)
        self.app_context = self.app.app_context()
        self.app_context.push()
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()

新的应用将存储在 self.app 中,但光是创建一个应用不足以使所有的工作都成功。 思考创建数据库表的 db.create_all() 语句。 db 实例需要注册到应用实例,因为它需要从 app.config 获取数据库 URI,但是当你使用应用工厂时,应用就不止一个了。 那么 db 如何关联到我刚刚创建的 self.app 实例呢?

答案在 application context 中。 还记得 current_app 变量吗?当不存在全局应用实例导入时,该变量以代理的形式来引用应用实例。 这个变量在当前线程中查找活跃的应用上下文,如果找到了,它会从中获取应用实例。 如果没有上下文,那么就没有办法知道哪个应用实例处于活跃状态,所以 current_app 就会引发一个异常。 下面你可以看到它是如何在 Python 控制台中工作的。 这需要通过运行 python 启动,因为 flask shell 命令会自动激活应用程序上下文以方便使用。

>>> from flask import current_app
>>> current_app.config['SQLALCHEMY_DATABASE_URI']
Traceback (most recent call last):
    ...
RuntimeError: Working outside of application context.

>>> from app import create_app
>>> app = create_app()
>>> app.app_context().push()
>>> current_app.config['SQLALCHEMY_DATABASE_URI']
'sqlite:////home/miguel/microblog/app.db'

这就是秘密所在! 在调用你的视图函数之前,Flask 推送一个应用上下文,它会使 current_appg 生效。 当请求完成时,上下文将与这些变量一起被删除。 为了使 db.create_all() 调用在单元测试 setUp() 方法中工作,我为刚刚创建的应用程序实例推送了一个应用上下文,这样 db.create_all() 可以使用 current_app.config 知道数据库在哪里。 然后在 tearDown() 方法中,我弹出上下文以将所有内容重置为干净状态。

你还应该知道,应用上下文是 Flask 使用的两种上下文之一,还有一个 请求上下文 ,它更具体,因为它适用于请求。 在处理请求之前激活请求上下文时,Flask 的 requestsession 以及 Flask-Login 的 current_user 变量才会变成可用状态。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文