繁体   English   中英

pytest ScopeMismatch错误:如何正确使用固定装置

[英]pytest ScopeMismatch error: how to use fixtures properly

对于以下代码:

@pytest.fixture(scope="module")
def dummy_article(request, db):
    return mixer.blend("core.article", title="this one price", internal_id=3000)


def test_article_str_method(dummy_article):
    assert (
        str(dummy_article)
        == f"article with ID {dummy_article.internal_id} and title: {dummy_article.title}"
    )

我收到以下错误:

ScopeMismatch: You tried to access the 'function' scoped fixture 'db' with a 'module' scoped request object, involved factories
core/tests/test_article_model.py:13:  def dummy_article(request, db)

如果我将固定装置更改为使用scope="function" ,则错误消失了,但这无法实现将其用于其他测试的目的,而不必为每个测试都“设置”。

我怎样才能拥有具有比function范围更广的db访问权限的灯具?

db Fixture具有function范围是有原因的,因此在每个测试结束时进行事务回滚可确保数据库保持与测试开始时相同的状态。 不过,您可以使用django_db_blocker固定装置,以会话/模块范围访问固定装置中的数据库:

@pytest.fixture(scope='module')
def get_all_models(django_db_blocker):
    with django_db_blocker.unblock():
        return MyModel.objects.all()

警告

请注意,在会话范围内解锁数据库时,如果您在其他固定装置或测试中更改数据库,则您将自己操劳。 在下面的示例中,我在会话范围内的夹具create_foo创建Foo的实体,然后在all_foos缓存会话的all_foos

# models.py

from django.db import models

class Foo(models.Model):
    name = models.CharField(max_length=16)


# test_foo.py

import pytest
from app.models import Foo

@pytest.fixture(scope='session', autouse=True)
def create_foo(django_db_blocker):
    with django_db_blocker.unblock():
        Foo.objects.create(name='bar')


@pytest.fixture(scope='module')
def all_foos(django_db_blocker):
    with django_db_blocker.unblock():
        yield Foo.objects.all()


def test_1(all_foos):
    assert all_foos.exists()

def test_2(all_foos, db):
    all_foos.delete()
    assert not Foo.objects.exists()

def test3(all_foos):
    assert all_foos.exists()

运行test_2之后,存储在会话中all_foos将为空,从而导致test_3失败:

test_foo.py::test_1 PASSED                                                           [ 33%]
test_foo.py::test_2 PASSED                                                           [ 66%]
test_foo.py::test_3 FAILED                                                           [100%]

========================================= FAILURES ========================================
__________________________________________ test_3 _________________________________________

all_foos = <QuerySet []>

    def test_3(all_foos):
>       assert all_foos.exists()
E       assert False
E        +  where False = <bound method QuerySet.exists of <QuerySet []>>()
E        +    where <bound method QuerySet.exists of <QuerySet []>> = <QuerySet []>.exists

test_foo.py:28: AssertionError

结果:如果您不想引入可能在测试中更改的全局状态,则切勿将引用存储在会话范围内。 从数据库查询数据并返回副本或序列化数据,依此类推。

安全使用示例:

@pytest.fixture(scope='session')
def foo_names(django_db_blocker):
    with django_db_blocker.unblock():
        names = list(Foo.objects.values_list('name', flat=True))
    return names

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM