私のdjangoアプリケーションユニットテストの1つが失敗します
DatabaseError: ORA-00942: table or view does not exist
このエラーの原因となった実際のSQLクエリを確認したいと思います。あなたはそれを達成する方法を知っていますか?
私のdjangoアプリケーションユニットテストの1つが失敗します
DatabaseError: ORA-00942: table or view does not exist
このエラーの原因となった実際のSQLクエリを確認したいと思います。あなたはそれを達成する方法を知っていますか?
テストからのすべての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つのオプションは、を使用することです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)
出典:
次の手順を実行してクエリを取得することもできます(たとえば、印刷したり、テストで評価したりできます)。
実は最近は変えてはいけない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
また、適切かもしれません。この回答の違いを参照してください。
SQL出力の詳細については、Djangoのドキュメントを参照してください。
別のオプションはconnection.execute_wrapper()
、次のようにテストで使用することです。
from django.db import connection
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()
Django2.2でテスト済み。
これは最もクリーンなソリューションではありませんが、追加のパッケージをインストールせずにすばやくデバッグしたい場合は、django / dbでexecute()メソッドを探すことができます。
Oracleの場合、次のようになります。
django / db / backends / oracle / base.pyを探して、次を探します。
def execute
PostgreSQLの場合は次のようになります。
django / db / backends / postgresql_psycopg2 / base.py
CursorWrapperには、execute()メソッドがあります。
どちらもIntegrityErrorとDatabaseErrorをキャッチしているので、そこにprintステートメントを追加できます。
すべてのSQLクエリを確認したいpplの場合は、関数呼び出しの直後にprintステートメントを配置します。
の場合、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,
},
}
}
私がこれまでに見つけた最善の解決策は、django-debugtoolbarが提供するdebugsqlshellカスタムdjango管理コマンドです。
設定でコンソールレベルをDEBUGに変更できます。Django1.9で動作しました。
LOGGING = {
...
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
}
...
}
これは私のために働いた解決策でした(Django3.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")