我的一个django应用程序单元测试失败了
DatabaseError: ORA-00942: table or view does not exist
我希望看到导致此错误的实际SQL查询。你知道如何实现这个目标吗?
答案 0 :(得分:17)
如果要从测试中打印/记录所有 SQL查询,请尝试按照以下方式对TestCase
进行子类化:
from django.conf import settings
from django.template import Template, Context
import sys
from django.db import connection
from django.test import TestCase
class LoggingTestCase(TestCase):
@staticmethod
def setUpClass():
# The test runner sets DEBUG to False. Set to True to enable SQL logging.
settings.DEBUG = True
super(LoggingTestCase, LoggingTestCase).setUpClass()
@staticmethod
def tearDownClass():
super(LoggingTestCase, LoggingTestCase).tearDownClass()
time = sum([float(q['time']) for q in connection.queries])
t = Template("{{count}} quer{{count|pluralize:\"y,ies\"}} in {{time}} seconds:\n\n{% for sql in sqllog %}[{{forloop.counter}}] {{sql.time}}s: {{sql.sql|safe}}{% if not forloop.last %}\n\n{% endif %}{% endfor %}")
print >> sys.stderr, t.render(Context({'sqllog': connection.queries, 'count': len(connection.queries), 'time': time}))
# Empty the query list between TestCases.
connection.queries = []
然后使用LoggingTestCase
代替TestCase
作为测试中的基类。如果你覆盖它,请记住调用此tearDownClass
。
答案 1 :(得分:5)
另一种选择是使用CaptureQueriesContext
(已通过pytest
测试)。
from django.db import connection
from django.test.utils import CaptureQueriesContext
def test_foo():
with CaptureQueriesContext(connection) as ctx:
# code that runs SQL queries
print(ctx.captured_queries)
来源:
答案 2 :(得分:3)
我到目前为止找到的最佳解决方案是django-debugtoolbar提供的debugsqlshell custom django management命令。
答案 3 :(得分:2)
它不是最干净的解决方案,但如果您只是想在不安装其他软件包的情况下快速调试,则可以在django / db中查找execute()方法。
对于 Oracle ,我猜它在:
django / db / backends / oracle / base.py并查找:
def execute
对于 PostgreSQL ,它位于:
django的/分贝/后端/ postgresql_psycopg2 / base.py
在CursorWrapper中有一个execute()方法。
两者都捕获IntegrityError和DatabaseError,您可以在那里添加print语句。
对于想要查看所有sql查询的ppl,请在函数调用之后立即放置print语句。
答案 4 :(得分:2)
您还可以执行以下操作来获取查询(然后打印或在测试中对其进行评估)。
实际上你现在shouldn't alter django.conf.settings
,因此我使用了override_settings
。
from django.db import connection, reset_queries
from django.test import override_settings, TransactionTestCase
class TransactionTests(TransactionTestCase):
@override_settings(DEBUG=True)
def test_sql(self):
reset_queries()
try:
# Code that uses the ORM goes here
except Exception as e:
pass
self.assertEqual(connection.queries, [])
TestCase
也可能适用,请参阅此answer中的差异。
有关SQL输出的详细信息,请参阅Django documentation。
答案 5 :(得分:0)
您可以在设置中将控制台级别更改为DEBUG。它适用于Django 1.9。
LOGGING = {
...
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
}
...
}
答案 6 :(得分:0)
另一种选择是在测试中使用connection.execute_wrapper()
,如下所示:
def logger(execute, sql, params, many, context):
print(sql, params)
return execute(sql, params, many, context)
class GizmoTest(TestCase):
def test_with_sql_logging(self):
with connection.execute_wrapper(logger):
code_that_uses_database()
经过Django 2.2的测试。
答案 7 :(得分:0)
对于pytest
和pytest-django
,只需为其创建一个夹具
@pytest.fixture
def debug_queries(db):
""" Because pytest run tests with DEBUG=False
the regular query logging will not work, use this fixture instead
"""
from django.db import connection
from django.test.utils import CaptureQueriesContext
with CaptureQueriesContext(connection):
yield connection
然后在您的测试中
@pytest.mark.django_db
def test__queries(debug_queries):
# run your queries here
当然,您的日志记录配置应启用查询日志记录,如下所示:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '%(asctime)s - %(levelname)s - %(name)s - %(message)s',
},
},
'handlers': {
'default': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'standard',
'stream': 'ext://sys.stdout',
},
},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['default'],
'propagate': False,
},
}
}
答案 8 :(得分:0)
这是对我有用的解决方案(Django 3.1):
from django.test import TestCase
class TestSomething(TestCase):
@override_settings(DEBUG=True)
def test_something(self):
pass
def tearDown(self):
from django.db import connection
for query in connection.queries:
print(f"✅ {query['sql']}\n")