这是我的测试代码:
import pytest
pytestmark = pytest.mark.django_db
from handy.db import do_sql, fetch_val
def setup_module(fetch_val):
print 1
do_sql('''
create table test (
id int primary key,
tag int not null
);
insert into test values (1, 10), (2, 20);
''')
print 2
def test_fetch_val():
print 3
assert fetch_val('select min(id) from test') == 1
我从test_fetch_val()
得到DatabaseError: relation "test" does not exist
test_fetch_val()
。 我也得到
2
Creating test database for alias 'default'...
3
捕获的输出。 看起来setup_module()
在创建数据库之前被调用。
django_db 标记基于夹具,我不确定如何在夹具和 setup_* 方法之间进行通信。
您可以使用模块范围的夹具来代替实现相同的功能吗? 即像
pytestmark = pytest.mark.usefixture('test_table')
@pytest.fixture(scope='module')
def test_table(db):
do_sql('create table ...')
def test_fetch_val():
assert fetch_val('...') == 1
刚试过。 没用。 我现在得到Database access not allowed, use the "django_db" mark to enable
。
另外, test_table()
不会运行(我试图在那里引发异常)
抱歉,应该是usefixtures,而不是usefixture:
现在我得到ScopeMismatchError: You tried to access the 'function' scoped funcarg 'db' with a 'module' scoped request object, involved factories
。
从参数中删除db
参数会导致夹具失败,删除 scope='module' 使认为可行,但随后为每个测试运行test_table()
,这是我不想要的。
我也试过
pytestmark = pytest.mark.django_db
@pytest.fixture(scope='module')
def test_table():
do_sql('''
create table test (
id int primary key,
tag int not null
);
insert into test values (1, 10), (2, 20);
''')
def test_fetch_val(test_table):
assert fetch_val('select min(id) from test') == 1
def test_fetch_val2(test_table):
assert fetch_val('select min(id) from test') == 1
这几乎有效,但第二次测试以某种方式失败了DatabaseError: relation "test" does not exist
。 对我来说完全是个谜。
Django 和 django_db 标记以每个测试用例在其自己的事务中运行的方式工作,因此将 django_db 与将数据插入数据库的模块级固定装置一起使用并没有真正意义。
你的用例是什么? 为什么您在测试中“手动”创建数据库表,而不是使用 Django,但仍想使用 Django 的测试数据库/测试数据库游标?
您不能通过构建一个普通的数据库游标来实现您所追求的目标吗?
(最后一个示例避免了 ScopeMismatchError,但它在测试中失败了,因为事务在第一次测试后回滚,因此回滚了测试表。)
我正在尝试测试几个在内部使用 django 游标的低级数据库实用程序 - https://github.com/Suor/handy/blob/master/handy/db.py#L40
而且我发现在models.py
定义模型然后在某些 django 格式中定义夹具来测试它会更加混乱。 这将是总共 3 个文件来测试非常基本的功能。
我只想在运行测试之前执行一些初始化代码,以便我可以使用一些数据。
哦,我成功了! 将初始化 SQL 包装到begin; ... commit;
有所帮助。
非常感谢您提供的所有提示。
这是一个对我来说看起来有点脆弱的黑客。 我可能会设置一个额外的应用程序,该应用程序仅用于使用简单模型进行测试,然后您可以使用它来运行这些函数。 然后,您可以轻松地使用 Django 的 ORM 来填充测试中的数据。 它的输入稍微多一些,还有一些额外的文件,但是对于将来的损坏应该是安全的。
如果其他人发现这个问题:在 setup_function/setup_class/setup_module 中进行数据库设置并不真正支持或不可能以任何好的方式进行,因为 pytest-django 的数据库设置基于夹具。
解决方案是使用正确请求 db 夹具的夹具:
http://pytest-django.readthedocs.org/en/latest/helpers.html#db
@pelme
使用db
固定装置,可以仅在函数范围内运行此类设置,而不是在类、模块或会话上。 例如,如果我们需要在执行类测试之前将一些记录填充到数据库中。
==================================== ERRORS ====================================
___________ ERROR at setup of TestHistoryAlerts.test_one_point_data ____________
ScopeMismatch: You tried to access the 'function' scoped fixture 'db' with a 'session' scoped request object, involved factories
tests/conftest.py:140: def ts(db)
../../../../.virtualenvs/app/lib/python2.7/site-packages/pytest_django/fixtures.py:158: def db(request, _django_db_setup, _django_cursor_wrapper)
有没有其他方法来处理它?
是的,这是当前实施的 db 固定装置的限制。 在 PR #258 中,有一些工作可以创建受类/模块/会话范围约束的数据库状态。
即使这个问题已经很老了,我发现找到解决pytest
和pytest-django
问题的解决方案很有用。 由于pytest 3.5.0
使用django_db
标记和module
级别装置时存在问题。
下面是在3.5.0
之前工作的(至少它没有引起任何问题)。
@pytest.fixture(scope='module')
def user():
return User.objects.create(...)
@pytest.mark.django_db
def test_some_case(user):
pass
在3.5.0
它提出
Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.
解决方案是删除scope='module'
。
+1 对我来说,只是从一些初始的 Djano 单元测试切换,这是一个主要的缺点,在为我的 API 测试用例初始化数据库时。 实际上支持会话/模块数据库装置应该是一个基本功能。 任何建议如何解决这个问题?
+1
最有用的评论
+1 对我来说,只是从一些初始的 Djano 单元测试切换,这是一个主要的缺点,在为我的 API 测试用例初始化数据库时。 实际上支持会话/模块数据库装置应该是一个基本功能。 任何建议如何解决这个问题?