使用pytest连接不同数据库

7 投票
2 回答
6407 浏览
提问于 2025-04-17 14:25

我在用pytest和pytest-django插件来测试我的django应用程序。我默认使用MySQL数据库。请问有没有办法让pytest在测试时使用不同的数据库,比如SQLite?

我想找其他的办法,而不是为pytest创建一个特别的test_settings.py文件,然后用命令--ds=test_settings来指定。

2 个回答

0

如果你需要在一个“真实”的数据库上跑测试,但又不想用你的主数据库,因为那样太慢了,你可以选择用sqlite来进行这个特定的测试。

import tempfile
from django.db import models, connections
from django.db.backends.sqlite3.base import DatabaseWrapper as SqliteConnection


@pytest.fixture(scope="function")
def sqlite_db(django_db_blocker):
    """
    Runs tests inside a sqlite3, making it slightly faster.
    When using this, avoid using the `@pytest.mark.django_db` and put the name `sqlite_db` as your
    first function parameter.

    Example:

        def test_something(sqlite_db):
            # This test will run inside a unique and isolated sqlite db

            with connection.cursor() as c, connection.schema_editor() as editor:
                editor.create_model(User)  # c.execute('CREATE TABLE ...')
                user = User.objects.create(username='test')  # c.execute('INSERT INTO ...')
                assert user.username == 'test'
                editor.delete_model(User)  # c.execute('DROP TABLE ...')
            
    """
    # Tells pytest-django that it's ok to use the db
    django_db_blocker.unblock()

    # Create a backup of the current db connection
    original_connection = connections['default']

    with tempfile.NamedTemporaryFile() as f:
        db_settings = {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': f.name,
            'TIME_ZONE': None,
            'CONN_MAX_AGE': 0,
            'OPTIONS': {},
            'AUTOCOMMIT': True,
        }
        # Override the `default` connection with the sqlite one
        connections['default'] = SqliteConnection(db_settings)

        # Call your test
        yield

        # Clean up
        connections['default'].close()
        # Put back the connection
        connections['default'] = original_connection

    # Tell pytest-django to restore the db lock
    django_db_blocker.restore()

注意: 示例测试(文档字符串)上没有 @pytest.mark.django_db 这个装饰器。

注意: 这样做会给你一个全新的数据库,里面什么都没有。如果你想用它,你需要先创建你的模型并填充数据。可以参考 editor = connections['default'].schema_editor(); editor.create_model(User),别忘了在用完后清理干净: editor.delete_model(User)

8

--ds=test_settings 是个不错的选择!

如果你不想每次运行 py.test 时都输入 --ds=...,你可以创建一个名为 pytest.ini 的文件,里面写上这些内容:

[pytest]
DJANGO_SETTINGS_MODULE = test_settings

顺便提一下:在运行测试时,使用和生产环境中相同类型的数据库是个好习惯。pytest-django 提供了 --reuse-db 这个选项,可以在测试运行之间重复使用 MySQL/Postgres 数据库,这样在测试很多模型的项目时,可以节省很多设置时间。

撰写回答