19

我的 django 应用程序单元测试之一失败

DatabaseError: ORA-00942: table or view does not exist

我想查看导致此错误的实际 SQL 查询。你知道如何实现吗?

4

9 回答 9

19

如果要打印/记录测试中的所有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如果您覆盖它,请记住调用它。

于 2013-08-28T09:39:13.047 回答
18

另一种选择是使用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)

资料来源:

于 2020-02-19T11:31:04.340 回答
9

您还可以执行以下操作来获取查询(然后例如在测试中打印或评估它)。

实际上你现在不应该改变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 文档

于 2018-04-19T09:33:54.513 回答
6

另一种选择是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()

用 Django 2.2 测试。

于 2019-07-13T17:42:31.417 回答
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,您可以在此处添加打印语句。

对于想要查看所有 sql 查询的 ppl,请将 print 语句放在函数调用之后。

于 2013-08-30T04:56:41.120 回答
1

在这种情况下pytestpytest-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,
        },
    }
}
于 2020-08-25T02:13:04.537 回答
0

到目前为止我找到的最好的解决方案是 django-debugtoolbar 提供的 debugsqlshell 自定义 django 管理命令。

于 2012-11-26T11:53:38.873 回答
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")

资源

于 2020-09-22T10:01:21.197 回答
0

您可以在设置中将控制台级别更改为调试。它适用于 Django 1.9。

LOGGING = {
...
'handlers': {
    'console': {
        'level': 'DEBUG',
        'class': 'logging.StreamHandler',
        'formatter': 'simple'
        },
    }
...
}
于 2017-08-22T05:53:21.363 回答