”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > Pytest 和 PostgreSQL:每次测试的新数据库

Pytest 和 PostgreSQL:每次测试的新数据库

发布于2024-08-21
浏览:756

Pytest and PostgreSQL: Fresh database for every test

在 Pytest(每个人最喜欢的 Python 测试框架)中,fixture 是一段可重用的代码,它在测试进入之前安排 something,并在测试退出后进行清理。例如,临时文件或文件夹、设置环境、启动 Web 服务器等。在这篇文章中,我们将了解如何创建 Pytest 夹具,该夹具创建一个测试数据库(空或已知状态),该数据库获取清理,允许每个测试在完全干净的数据库上运行

目标

我们将使用 Psycopg 3 创建一个 Pytest 夹具来准备和清理测试数据库。因为空数据库对测试几乎没有帮助,所以我们将选择应用 Yoyo 迁移(在撰写本文时网站已关闭,请转到 archive.org 快照)来填充它。

因此,在此博文中创建的名为 test_db 的 Pytest 夹具的要求是​​:

  • 删除测试数据库如果在测试之前存在
  • 在测试之前创建一个空数据库
  • 可选地
  • 在测试之前应用迁移或创建测试数据
  • 提供到测试数据库的连接到测试
  • 测试后删除测试数据库(即使失败)
通过列出测试方法参数来请求它的任何测试方法:


def test_create_admin_table(test_db): ...
def test_create_admin_table(test_db):
    ...
将收到连接到测试数据库的常规 Psycopg 连接实例。测试可以做任何它需要的事情,就像普通的 Psycopg 常见用法一样,例如:


def test_create_admin_table(test_db): # 打开游标执行数据库操作 cur = test_db.cursor() # 传递数据来填充查询占位符并让 Psycopg 执行 # 正确的转换(没有 SQL 注入!) 当前.执行( “插入测试(数字,数据)值(%s,%s)”, (100,“abc'def”)) # 查询数据库并获取数据作为Python对象。 cur.execute("从测试中选择*") cur.fetchone() # 将返回 (1, 100, "abc'def") # 你可以使用 `cur.fetchmany()`, `cur.fetchall()` 返回一个列表 # 多个记录,甚至在光标上迭代 以 cur 记录: 打印(记录)
def test_create_admin_table(test_db):
    ...

动机和替代方案 看起来有一些 Pytest 插件承诺为依赖数据库的测试提供 PostgreSQL 固定装置。它们可能很适合你。
我尝试过 pytest-postgresql 它承诺相同。在编写自己的装置之前我已经尝试过它,但我无法让它为我工作。也许是因为他们的文档让我很困惑。

另一个,pytest-dbt-postgres,我根本没有尝试过。



项目文件布局

在经典的Python项目中,源代码位于src/中,测试位于tests/中:


├── src │ └── 杜沃克 │ ├── __init__.py │ └── 销售 │ └── new_user.py ├── 测试 │ ├──conftest.py │ └── 销售 │ └── test_new_user.py ├── 需求.txt └── yoyo.ini
def test_create_admin_table(test_db):
    ...
如果你使用像梦幻般的Yoyo这样的迁移库,迁移脚本可能在migrations/:


├── 迁移 ├── 20240816_01_Yn3Ca-sales-user-user-add-last-run-table.py ├── ...
def test_create_admin_table(test_db):
    ...
配置

我们的测试数据库夹具需要很少的配置:

  • 连接 URL - (无数据库)
  • 测试数据库名称 - 将为每个测试重新创建
  • (可选)
  • 迁移文件夹 - 应用于每个测试的迁移脚本
Pytest 有一个天然的地方 conftest.py 用于跨多个文件共享固定装置。灯具配置也会在那里:


# 没有数据库名称! TEST_DB_URL = “postgresql://localhost” TEST_DB_NAME =“test_tuvok” TEST_DB_MIGRATIONS_DIR = str(Path(__file__, "../../migrations").resolve())
def test_create_admin_table(test_db):
    ...
您可以从环境变量或任何适合您情况的值中设置这些值。

创建 test_db 夹具

了解

PostgreSQL和Psycopg库,在conftest.py中编写fixture:

@pytest.fixture def test_db(): # autocommit=True 不启动事务,因为 CREATE/DROP DATABASE # 不能在事务块中执行。 使用 psycopg.connect(TEST_DB_URL, autocommit=True) 作为 conn: cur = conn.cursor() # 创建测试数据库,之前删除 cur.execute(f'如果存在“{TEST_DB_NAME}”则删除数据库(FORCE)') cur.execute(f'创建数据库“{TEST_DB_NAME}”') # 返回到刚刚创建的测试数据库的(新)连接 # 不幸的是,您无法直接更改现有 Psycopg 连接的数据库。一旦建立了与特定数据库的连接,它就与该数据库绑定在一起。 使用 psycopg.connect(TEST_DB_URL, dbname=TEST_DB_NAME) 作为 conn: 产量康涅狄格州 cur.execute(f'如果存在“{TEST_DB_NAME}”则删除数据库(FORCE)')
def test_create_admin_table(test_db):
    ...
创建迁移固定装置

在我们的例子中,我们使用

Yoyo 迁移。将应用迁移编写为另一个名为 yoyo 的固定装置:

@pytest.fixture def yoyo(): # Yoyo 期望 `driver://user:pass@host:port/database_name?param=value`。 # 在传递的 URL 中我们需要 网址 = ( urlparse(TEST_DB_URL) 。 # 1) 使用 `postgresql psycopg` 更改驱动程序(架构部分)以使用 # psycopg 3(不是 2,即 `postgresql psycopg2`) _replace(scheme="postgresql psycopg") 。 # 2) 将数据库更改为测试数据库(其中将应用迁移) _replace(路径=TEST_DB_NAME) .geturl() ) 后端 = get_backend(url) 迁移 = read_migrations(TEST_DB_MIGRATIONS_DIR) 如果 len(迁移) == 0: raise ValueError(f"在 '{TEST_DB_MIGRATIONS_DIR}' 中找不到 Yoyo 迁移'") 与 backend.lock(): backend.apply_migrations(backend.to_apply(迁移))
def test_create_admin_table(test_db):
    ...
如果你想

将迁移应用到每个测试数据库,需要 yoyo 夹具用于 test_db 夹具:

@pytest.fixture def test_db(yoyo): ...
def test_create_admin_table(test_db):
    ...

仅将迁移应用于某些测试,需要单独使用 yoyo:

def test_create_admin_table(test_db, yoyo): ...
def test_create_admin_table(test_db):
    ...
结论

构建自己的装置来为您的测试提供一个干净的数据库对我来说是一次有益的经历,让我能够更深入地研究 Pytest 和 Postgres。

我希望本文对您自己的数据库测试套件有所帮助。请随时在评论中留下您的问题并祝您编码愉快!

版本声明 本文转载于:https://dev.to/liborjelinek/pytest-and-postgresql-fresh-database-for-every-test-4eni?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    使用 JSTL 迭代 HashMap 中的 ArrayList在 Web 开发中,JSTL(JavaServer Pages 标准标记库)提供了一组标记来简化 JSP 中的常见任务( Java 服务器页面)。其中一项任务是迭代数据结构。要迭代 HashMap 及其中包含的 ArrayList,可以使...
    编程 发布于2024-11-05
  • Encore.ts — 比 ElysiaJS 和 Hono 更快
    Encore.ts — 比 ElysiaJS 和 Hono 更快
    几个月前,我们发布了 Encore.ts — TypeScript 的开源后端框架。 由于已经有很多框架,我们想分享我们做出的一些不常见的设计决策以及它们如何带来卓越的性能数据。 性能基准 我们之前发布的基准测试显示 Encore.ts 比 Express 快 9 倍,比 Fasti...
    编程 发布于2024-11-05
  • 为什么使用 + 对字符串文字进行字符串连接失败?
    为什么使用 + 对字符串文字进行字符串连接失败?
    连接字符串文字与字符串在 C 中,运算符可用于连接字符串和字符串文字。但是,此功能存在限制,可能会导致混乱。在问题中,作者尝试连接字符串文字“Hello”、“,world”和“!”以两种不同的方式。第一个例子:const string hello = "Hello"; const...
    编程 发布于2024-11-05
  • React 重新渲染:最佳性能的最佳实践
    React 重新渲染:最佳性能的最佳实践
    React高效的渲染机制是其受欢迎的关键原因之一。然而,随着应用程序复杂性的增加,管理组件重新渲染对于优化性能变得至关重要。让我们探索优化 React 渲染行为并避免不必要的重新渲染的最佳实践。 1. 使用 React.memo() 作为函数式组件 React.memo() 是一个高...
    编程 发布于2024-11-05
  • 如何实现条件列创建:探索 Pandas DataFrame 中的 If-Elif-Else?
    如何实现条件列创建:探索 Pandas DataFrame 中的 If-Elif-Else?
    Creating a Conditional Column: If-Elif-Else in Pandas给定的问题要求将新列添加到 DataFrame 中基于一系列条件标准。挑战在于在实现这些条件的同时保持代码效率和可读性。使用函数应用程序的解决方案一种方法涉及创建一个将每一行映射到所需结果的函数...
    编程 发布于2024-11-05
  • 介绍邱!
    介绍邱!
    我很高兴地宣布发布 Qiu – 一个严肃的 SQL 查询运行器,旨在让原始 SQL 再次变得有趣。老实说,ORM 有其用武之地,但当您只想编写简单的 SQL 时,它们可能会有点让人不知所措。我一直很喜欢编写原始 SQL 查询,但我意识到我需要练习——大量的练习。这就是Qiu发挥作用的地方。 有了 Q...
    编程 发布于2024-11-05
  • 为什么 CSS 中的 Margin-Top 百分比是根据容器宽度计算的?
    为什么 CSS 中的 Margin-Top 百分比是根据容器宽度计算的?
    CSS 中的 margin-top 百分比计算当对元素应用 margin-top 百分比时,必须了解计算方式执行。与普遍的看法相反,边距顶部百分比是根据包含块的宽度而不是其高度来确定的。W3C 规范解释:根据W3C 规范,“百分比是根据生成的框包含块的宽度计算的。”此规则适用于“margin-top...
    编程 发布于2024-11-05
  • 如何解决 CSS 转换期间 Webkit 文本渲染不一致的问题?
    如何解决 CSS 转换期间 Webkit 文本渲染不一致的问题?
    解决 CSS 转换期间的 Webkit 文本渲染不一致在 CSS 转换期间,特别是缩放元素时,Webkit 中可能会出现文本渲染不一致的情况浏览器。这个问题源于浏览器尝试优化渲染性能。一种解决方案是通过添加以下属性来强制对过渡元素的父元素进行硬件加速:-webkit-transform: trans...
    编程 发布于2024-11-05
  • 使用 Reactables 简化 RxJS
    使用 Reactables 简化 RxJS
    介绍 RxJS 是一个功能强大的库,但众所周知,它的学习曲线很陡峭。 该库庞大的 API 界面,再加上向反应式编程的范式转变,可能会让新手不知所措。 我创建了 Reactables API 来简化 RxJS 的使用并简化开发人员对反应式编程的介绍。 例子 我们将构建...
    编程 发布于2024-11-05
  • 如何在 Pandas 中查找多列的最大值?
    如何在 Pandas 中查找多列的最大值?
    查找 Pandas 中多列的最大值要确定 pandas DataFrame 中多列的最大值,可以采用多种方法。以下是实现此目的的方法:对指定列使用 max() 函数此方法涉及显式选择所需的列并应用 max() 函数: df[["A", "B"]] df[[&q...
    编程 发布于2024-11-05
  • CI/CD 入门:自动化第一个管道的初学者指南(使用 Jenkins)
    CI/CD 入门:自动化第一个管道的初学者指南(使用 Jenkins)
    目录 介绍 什么是 CI/CD? 持续集成(CI) 持续交付(CD) 持续部署 CI/CD 的好处 更快的上市时间 提高代码质量 高效协作 提高自动化程度和一致性 如何创建您的第一个 CI/CD 管道 第 1 步:设置版本控制 (GitHub) 第 2 步:选择 CI/CD 工具 ...
    编程 发布于2024-11-05
  • TypeScript 如何使 JavaScript 在大型项目中更加可靠。
    TypeScript 如何使 JavaScript 在大型项目中更加可靠。
    介绍 JavaScript 广泛应用于 Web 开发,现在也被应用于不同行业的大型项目中。然而,随着这些项目的增长,管理 JavaScript 代码变得更加困难。数据类型不匹配、运行时意外错误以及代码不清晰等问题可能会导致查找和修复错误变得困难。 这就是TypeScript介入的地...
    编程 发布于2024-11-05
  • 如何使用PHP的password_verify函数安全地验证用户密码?
    如何使用PHP的password_verify函数安全地验证用户密码?
    使用 PHP 解密加密密码许多应用程序使用密码哈希等加密算法安全地存储用户密码。然而,在验证登录尝试时,将输入密码与加密的存储版本进行比较非常重要。加密问题password_hash 使用 Bcrypt,一种一元加密算法方式哈希算法,意味着加密的密码无法逆转或解密。这是一项安全功能,可确保即使数据库...
    编程 发布于2024-11-05
  • 学习 Vue 部分 构建天气应用程序
    学习 Vue 部分 构建天气应用程序
    深入研究 Vue.js 就像在 DIY 工具包中发现了一个新的最喜欢的工具——直观、灵活,而且功能强大得惊人。我接触 Vue 的第一个副业项目是一个天气应用程序,它教会了我很多关于框架功能以及一般 Web 开发的知识。这是我到目前为止所学到的。 1. Vue 入门:简单与强大 Vue...
    编程 发布于2024-11-05
  • NFT 预览卡组件
    NFT 预览卡组件
    ?刚刚完成了我的最新项目:使用 HTML 和 CSS 的“NFT 预览卡组件”! ?查看并探索 GitHub 上的代码。欢迎反馈! ? GitHub:[https://github.com/khanimran17/NFT-preview-card-component] ?现场演示:[https://...
    编程 发布于2024-11-05

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3