Pytest 和 PostgreSQL:每次测试的新数据库
在 Pytest(每个人最喜欢的 Python 测试框架)中,fixture 是一段可重用的代码,它在测试进入之前安排 某些内容,并在测试退出后进行清理。例如,临时文件或文件夹、设置环境、启动 Web 服务器等。在这篇文章中,我们将了解如何创建一个 Pytest 夹具,该夹具创建一个测试数据库(空或具有已知状态),该数据库获取清理,允许每个测试在完全干净的数据库上运行。
目标
我们将使用 Psycopg 3 创建一个 Pytest 夹具来准备和清理测试数据库。因为空数据库对测试几乎没有帮助,所以我们将选择应用 Yoyo 迁移(在撰写本文时网站已关闭,请转到 archive.org 快照)来填充它。
因此,对本博文中创建的名为 test_db 的 Pytest 夹具的要求是:
- 删除测试数据库如果在测试之前存在
- 测试前创建一个空数据库
- 可选地在测试之前应用迁移或创建测试数据
- 提供到测试数据库的连接到测试
- 测试后删除测试数据库(即使失败)
通过列出测试方法参数来请求它的任何测试方法:
def test_create_admin_table(test_db): ...
将收到连接到测试数据库的常规 Psycopg 连接实例。测试可以做任何它需要的事情,就像普通的 Psycopg 常见用法一样,例如:
def test_create_admin_table(test_db): # Open a cursor to perform database operations cur = test_db.cursor() # Pass data to fill a query placeholders and let Psycopg perform # the correct conversion (no SQL injections!) cur.execute( "INSERT INTO test (num, data) VALUES (%s, %s)", (100, "abc'def")) # Query the database and obtain data as Python objects. cur.execute("SELECT * FROM test") cur.fetchone() # will return (1, 100, "abc'def") # You can use `cur.fetchmany()`, `cur.fetchall()` to return a list # of several records, or even iterate on the cursor for record in cur: print(record)
我尝试过 pytest-postgresql,它也有同样的承诺。在编写自己的装置之前我已经尝试过它,但我无法让它为我工作。也许是因为他们的文档让我很困惑。 另一个,pytest-dbt-postgres,我根本没有尝试过。动机和替代方案
看起来有一些 Pytest 插件承诺为依赖数据库的测试提供 PostgreSQL 固定装置。它们可能很适合你。
项目文件布局
在经典的Python项目中,源代码位于src/中,测试位于tests/中:
├── src │ └── tuvok │ ├── __init__.py │ └── sales │ └── new_user.py ├── tests │ ├── conftest.py │ └── sales │ └── test_new_user.py ├── requirements.txt └── yoyo.ini
如果你使用像梦幻般的Yoyo这样的迁移库,迁移脚本可能位于migrations/:
├── migrations ├── 20240816_01_Yn3Ca-sales-user-user-add-last-run-table.py ├── ...
配置
我们的测试数据库装置需要很少的配置:
- 连接 URL -(无数据库)
- 测试数据库名称 - 将为每个测试重新创建
- (可选)迁移文件夹 - 应用于每个测试的迁移脚本
Pytest 有一个天然的地方 conftest.py 用于跨多个文件共享固定装置。灯具配置也会在那里:
# Without DB name! TEST_DB_URL = "postgresql://localhost" TEST_DB_NAME = "test_tuvok" TEST_DB_MIGRATIONS_DIR = str(Path(__file__, "../../migrations").resolve())
您可以从环境变量或任何适合您情况的值中设置这些值。
创建 test_db 夹具
了解PostgreSQL和Psycopg库,在conftest.py中编写fixture:
@pytest.fixture def test_db(): # autocommit=True start no transaction because CREATE/DROP DATABASE # cannot be executed in a transaction block. with psycopg.connect(TEST_DB_URL, autocommit=True) as conn: cur = conn.cursor() # create test DB, drop before cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB_NAME}" WITH (FORCE)') cur.execute(f'CREATE DATABASE "{TEST_DB_NAME}"') # Return (a new) connection to just created test DB # Unfortunately, you cannot directly change the database for an existing Psycopg connection. Once a connection is established to a specific database, it's tied to that database. with psycopg.connect(TEST_DB_URL, dbname=TEST_DB_NAME) as conn: yield conn cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB_NAME}" WITH (FORCE)')
创建迁移固定装置
在我们的例子中,我们使用Yoyo 迁移。将应用迁移编写为另一个名为 yoyo 的固定装置:
@pytest.fixture def yoyo(): # Yoyo expect `driver://user:pass@host:port/database_name?param=value`. # In passed URL we need to url = ( urlparse(TEST_DB_URL) . # 1) Change driver (schema part) with `postgresql+psycopg` to use # psycopg 3 (not 2 which is `postgresql+psycopg2`) _replace(scheme="postgresql+psycopg") . # 2) Change database to test db (in which migrations will apply) _replace(path=TEST_DB_NAME) .geturl() ) backend = get_backend(url) migrations = read_migrations(TEST_DB_MIGRATIONS_DIR) if len(migrations) == 0: raise ValueError(f"No Yoyo migrations found in '{TEST_DB_MIGRATIONS_DIR}'") with backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
如果你想将迁移应用到每个测试数据库,需要 yoyo 夹具用于 test_db 夹具:
@pytest.fixture def test_db(yoyo): ...
要仅将迁移应用于某些测试,需要单独使用yoyo:
def test_create_admin_table(test_db, yoyo): ...
结论
构建自己的装置来为您的测试提供一个干净的数据库对我来说是一次有益的经历,让我能够更深入地研究 Pytest 和 Postgres。
我希望本文对您自己的数据库测试套件有所帮助。请随时在评论中留下您的问题,祝您编码愉快!
以上是Pytest 和 PostgreSQL:每次测试的新数据库的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Python在游戏和GUI开发中表现出色。1)游戏开发使用Pygame,提供绘图、音频等功能,适合创建2D游戏。2)GUI开发可选择Tkinter或PyQt,Tkinter简单易用,PyQt功能丰富,适合专业开发。

Python更易学且易用,C 则更强大但复杂。1.Python语法简洁,适合初学者,动态类型和自动内存管理使其易用,但可能导致运行时错误。2.C 提供低级控制和高级特性,适合高性能应用,但学习门槛高,需手动管理内存和类型安全。

要在有限的时间内最大化学习Python的效率,可以使用Python的datetime、time和schedule模块。1.datetime模块用于记录和规划学习时间。2.time模块帮助设置学习和休息时间。3.schedule模块自动化安排每周学习任务。

Python在开发效率上优于C ,但C 在执行性能上更高。1.Python的简洁语法和丰富库提高开发效率。2.C 的编译型特性和硬件控制提升执行性能。选择时需根据项目需求权衡开发速度与执行效率。

pythonlistsarepartofthestAndArdLibrary,herilearRaysarenot.listsarebuilt-In,多功能,和Rused ForStoringCollections,而EasaraySaraySaraySaraysaraySaraySaraysaraySaraysarrayModuleandleandleandlesscommonlyusedDduetolimitedFunctionalityFunctionalityFunctionality。

Python在自动化、脚本编写和任务管理中表现出色。1)自动化:通过标准库如os、shutil实现文件备份。2)脚本编写:使用psutil库监控系统资源。3)任务管理:利用schedule库调度任务。Python的易用性和丰富库支持使其在这些领域中成为首选工具。

每天学习Python两个小时是否足够?这取决于你的目标和学习方法。1)制定清晰的学习计划,2)选择合适的学习资源和方法,3)动手实践和复习巩固,可以在这段时间内逐步掌握Python的基本知识和高级功能。

Python和C 各有优势,选择应基于项目需求。1)Python适合快速开发和数据处理,因其简洁语法和动态类型。2)C 适用于高性能和系统编程,因其静态类型和手动内存管理。
