[英]How to write clean tests on model with database access
我正在使用 SQLAlchemy + Ormar 并且我想编写干净的测试,因为它可以使用pytest-django编写:
import pytest
@pytest.mark.django_db
def test_user_count():
assert User.objects.count() == 0
我正在使用 FastAPI 而根本没有使用 Django 所以无法使用上述装饰器。
如何使用上述数据库访问权限在 model 上编写干净的测试,但不使用 Django。 拥有 SQLAlchemy + Ormar 的基础设施会很棒,但更改 ORM 也是一种选择。
model 示例进行测试:
class User(ormar.Model):
class Meta:
metadata = metadata
database = database
id: int = ormar.BigInteger(primary_key=True)
phone: str = ormar.String(max_length=100)
account: str = ormar.String(max_length=100)
我认为这个讨论对你有用https://github.com/collerek/ormar/discussions/136
使用 autouse 固定装置应该可以帮助您:
# fixture
@pytest.fixture(autouse=True, scope="module") # adjust your scope
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine) # i like to drop also before - even if test crash in the middle we start clean
metadata.create_all(engine)
yield
metadata.drop_all(engine)
# actual test - note to test async you need pytest-asyncio and mark test as asyncio
@pytest.mark.asyncio
async def test_actual_logic():
async with database: # <= note this is the same database that used in ormar Models
... (logic)
这是我在项目根目录中的独立脚本(笔记本)使用的, manage.py
所在的位置;
import sys, os, django
# append your project to your path
sys.path.append("./<your-project>")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<your-project>.settings")
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" # for notebooks only
django.setup()
# import the model
from listings.models import Listing
但是,应该注意的是 Django 带有它自己的单元测试。 看看这里。 这将使您能够使用python3 manage.py test <your-test>
运行测试。
这里发生了一些神奇的事情(但这在pytest
中通常是正确的)。 @pytest.mark.django_db
夹具只是标记测试,但它自己并没有做太多其他事情。 繁重的工作稍后发生在 pytest-django 内部,插件将过滤/扫描带有该标记的测试并向它们添加适当的固定装置。
我们可以复制这种行为:
# conftest.py (or inside a dedicated plugin, if you fancy)
import pytest
# register the custom marker called my_orm
def pytest_configure(config):
config.addinivalue_line(
"markers", "my_orm: This test uses my ORM to connect to my DB."
)
@pytest.fixture()
def setup_my_orm():
print("TODO: set up DB and connect.")
yield
print("TODO: tear down DB and disconnect.")
# this is where the magic happens
def pytest_runtest_setup(item):
needs_my_orm = len([marker for marker in item.iter_markers(name="my_orm")]) > 0
if needs_my_orm and "setup_my_orm" not in item.fixturenames:
item.fixturenames.append("setup_my_orm")
# test_mymodule.py
@pytest.mark.my_orm
def test_foo():
assert 0 == 0
您可以通过pytest -s
检查测试是否确实打印了上述 TODO 语句。
当然,您可以使用标记的参数、更复杂的夹具范围等进一步自定义它。但是,这应该让您走上正确的轨道:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.