代码之家  ›  专栏  ›  技术社区  ›  kurtgn

pytest django:无法访问fixture teardown中的db

  •  1
  • kurtgn  · 技术社区  · 7 年前

    在使用fixture之后,我需要显式地删除它。我知道pytest django默认情况下会删除所有对象,但在这种情况下,我需要手动完成。但是,尽管我的测试标记为 pytest.mark.django_db ,我可以创建fixture,但无法在 yield

    import pytest
    
    from tgapps.models import TelegramApp
    
    
    @pytest.fixture(scope='module')
    def some_fixture():
    
        app = TelegramApp.objects.create(
            session_data=b'\xa2\x8f#',
            app_owner_phone=79856235474,
            app_id=182475,
            app_hash='aad9ab4384fea1af0342b77b606d13b0'
        )
        yield app
    
        print('deleting object...')
        app.delete()
    
    
    class TestTelegramServiceObject(object):
    
        @pytest.mark.django_db
        def test1(self, some_fixture):
            print('Fixture created:')
            print(some_fixture)
    

    这是我的测试输出:

    ============================= test session starts ==============================
    platform darwin -- Python 3.6.4, pytest-3.4.0, py-1.5.2, pluggy-0.6.0
    Django settings: inviter.settings.staging (from ini file)
    rootdir: /Users/1111/_projects/fasttrack/inviter, inifile: pytest.ini
    plugins: mock-1.7.1, dotenv-0.1.0, django-3.1.2
    collected 1 item
    test_example.py E.Fixture created:
    <79856235474 - 182475>
    deleting object...
    
    tests/api/test_example.py:25 (TestTelegramServiceObject.test1)
    @pytest.fixture(scope='module')
        def some_fixture():
    
            app = TelegramApp.objects.create(
                session_data=b'\xa2\x8f#',
                app_owner_phone=79856235474,
                app_id=182475,
                app_hash='aad9ab4384fea1af0342b77b606d13b0'
            )
            yield app
    
            print('deleting object...')
    >       app.delete()
    
    test_example.py:21: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    /Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/base.py:890: in delete
        collector.collect([self], keep_parents=keep_parents)
    /Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/deletion.py:221: in collect
        elif sub_objs:
    /Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/query.py:276: in __bool__
        self._fetch_all()
    /Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/query.py:1179: in _fetch_all
        self._result_cache = list(self._iterable_class(self))
    /Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/query.py:53: in __iter__
        results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
    /Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/sql/compiler.py:1062: in execute_sql
        cursor = self.connection.cursor()
    /Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/backends/base/base.py:255: in cursor
        return self._cursor()
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <django.db.backends.postgresql.base.DatabaseWrapper object at 0x1048bf080>
    name = None
    
        def _cursor(self, name=None):
    >       self.ensure_connection()
    E       Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.
    

    1 回复  |  直到 7 年前
        1
  •  0
  •   Andreas Profous    6 年前

    你需要 db 某些设备中的设备:

    def some_fixture(db): ...

        2
  •  0
  •   Tom    5 年前

    这个 db Andreas Profous提到的fixture是函数范围的,因此在这里不起作用。

    你需要做的是:

    @pytest.fixture(scope='module')
    def some_fixture(django_db_setup, django_db_blocker):
        with django_db_blocker.unblock():
            app = TelegramApp.objects.create(
                session_data=b'\xa2\x8f#',
                app_owner_phone=79856235474,
                app_id=182475,
                app_hash='aad9ab4384fea1af0342b77b606d13b0'
            )
        yield app
        with django_db_blocker.unblock():
            print('deleting object...')
            app.delete()
    

    django_db_setup django_db_blocker 是什么 分贝 fixture用于允许函数范围的修改。它函数作用域的原因是它的行为方式 TestCase 方法在默认的unittest框架中运行,在该框架中,记录在每次测试后都会回滚。这是一件好事,它确保在一个测试中修改一个记录不会在另一个测试中更改结果。

    因此,在创建不受函数作用域限制的fixture时要非常小心,因为您的修改默认情况下不会包装在事务中并回滚。使用 django_db_阻滞剂 把钩子钩住 django_db_blocker.unblock()