【问题标题】:How to not roll back db transactions created in pytest-django fixture of class scope如何不回滚在类范围的 pytest-django 夹具中创建的数据库事务
【发布时间】:2017-05-23 12:01:13
【问题描述】:

我正在将 pytest 与 Django 一起使用(通过 pytest-django),我想知道是否有可能有一个范围为 class 的夹具,它在数据库中创建一些模型,然后 不是在每次测试结束时删除这些模型。

例如;

@pytest.fixture(scope='class')
def expensive():
    return MyModel.objects.create()


@pytest.mark.django_db()
class TestMyModel:

    def test_a(self, expensive):
          MyModel.objects.get()  # All good

    def test_b(self, expensive):
          MyModel.objects.get()  # raises MyModel.DoesNotExist             

这只是一个简化的示例,在我的实际代码中,夹具 expensive 实际上正在做一些需要一些时间的事情(我实际上正在使用参数化测试,但我想这不会有任何区别)。我的愿望是在夹具expensive 中创建的数据一旦超出类的范围就会回滚,以免干扰其他测试。

使用夹具django_db_blocker 似乎可以实现我想要做的事情,但是我无法让它按我想要的方式运行。

【问题讨论】:

  • 你想在每次测试后回滚更改还是在整个测试周期中保留它,问题的标题说 not rollback 但测试描述说 > 我的愿望是在fixture中创建的数据一旦超出类的范围就会回滚,以免干扰其他测试
  • 我想保留expensive 中发生的所有事务,同时回滚任一测试中发生的事务。

标签: python django pytest pytest-django


【解决方案1】:

在过去的几天里,我一直在为同样的问题苦苦挣扎,并设法想出了一个几乎适用于所有情况的解决方案。它是基于pytest-django 源的一种黑客攻击。如果将其添加到测试类中,请确保不要添加任何内置的 pytest-django db 标记。

import psycopg2
from django.apps import apps
from django.test.utils import setup_databases, teardown_databases
# alternatively if you're not on django 1.11 you need
# from pytest_django.compat import setup_databases, teardown_databases

@pytest.fixture(scope='class')
def class_scoped_db(django_db_blocker):
    try:
        django_db_blocker.unblock()
        # if test db exists use it and delete all objects once done
        _ = psycopg2.connect(dbname='test_{your_db_name}')
        yield
        # drop all objects created once we are out of scope
        for app_name in {list of your django apps}:
            for model in apps.get_app_config(app_name).get_models():
                model.objects.all().delete()

    except psycopg2.OperationalError:
        # if test db doesn't exist then create one and tear down once done
        db_cfg = setup_databases(verbosity=pytest.config.option.verbose,
                                 interactive=False)
        yield
        teardown_databases(db_cfg, verbosity=pytest.config.option.verbose)

    finally:
        django_db_blocker.restore()

我发现它不起作用的一个情况是,当需要数据库访问的第一个运行的测试使用class_scoped_db时,我认为拆解方法使数据库连接处于一种奇怪的状态,剩下的测试无法使用。在完整的测试运行或测试单个测试类或模块时对我来说效果很好

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多