Django 如何在单元测试的时候也打印 SQL 语句 前言

前言

自己动手丰衣足食

之前在 思否 提了这个问题,但是没人回答啊,那就只能自己解决了!

Django 如何在单元测试的时候也打印 SQL 语句

不仅仅是思否,stackoverflow 不过都没有人回答

如何输出 SQL 语句

在项目的 settings.py 文件中添加如下内容就可以将一切对数据库的操作翻译为 SQL 语句,但是注意这个模式只有在 settings.py 中的 DEBUG 开关为 True 是才有效!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
python复制代码LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}

在单元测试中输出 SQL 语句的需求

上面的语句在做单元测试的时候就变得不好使!

根本就不输出 SQL 语句!!!

我一开始以为是上面代码中的 level 设置的不对,应该将 DEBUG 改为 生产,当然,答案并非如此!

找寻答案

为什么会有这个需求呢?其实还是为了调试代码方便嘛,但既然是调试代码,如果涉及数据库的操作却不输出 SQL 语句,就感觉是雾里看花、黑箱操作让人摸不着头脑!!!作为一名优秀的程序员怎么能允许这种事情发生呢?当然不可以!!!

所以我去通读了 Django 官方文档中相关的内容

通过阅读改文档可知:做单元测试的时候会以生产模式运行,这就解释了为什么不输出 SQL 语句,因为我们的日志设置的级别是 DEBUG

无论配置文件中的 DEBUG 设置值是多少,所有的 Django 测试都以 DEBUG=False 运行。这是为了确保你的代码观察到的输出与生产环境下的输出一致。

好的,找到了改进方向了,那就 level 改为生产模式就好了嘛!

但是通过阅读文档发现只有:

+ `DEBUG`:排查故障时使用的低级别系统信息
+ `INFO`:一般的系统信息
+ `WARNING`:描述系统发生了一些小问题的信息
+ `ERROR`:描述系统发生了大问题的信息
+ `CRITICAL`:描述系统发生严重问题的信息这五种模式,最低就是 DEBUG,根本没有生产模式啊!!!

读完该篇文档,我懂了,之前想要修改 level 的想法是错误的,我们可以也应该通过自定义测试器 的方式来让单元测试也输出 SQL 语句!!!

说干就干!

说干就干

在根目录下面新建一个 testing 文件夹,然后在其中创建一个 testcases.py 文件,在其中写下如下的代码:

1
2
3
4
5
6
python复制代码from django.test.runner import DiscoverRunner


class DebugDiscoverRunner(DiscoverRunner):
def __init__(self, *args, **kwargs):
super().__init__(debug_sql=True, verbosity=2)

这段代码有几个关键点

  • 继承 DiscoverRunner

这个没什么好说的,默认就是 DiscoverRunner,所以我们继承他

  • debug_sql=True, verbosity=2

继承它不为别的,就像开启上面的两个参数

testingtestcases.py 这些名字随意,只是我习惯这么放置和取名字,你随意!!!

然后再 settings.py 文件中的任意位置添加下面的代码:

1
python复制代码TEST_RUNNER = 'testing.testrunner.DebugDiscoverRunner'

这个时候你只需要再终端输入

1
bash复制代码python manage.py test

就会调用我们的 DebugDiscoverRunner 来做单元测试,执行 __init__.py 传递 debug_sql=True, verbosity=2 ,就会再控制台源源不断的打印 SQL 语句!!!

一些细节

你会发现 DebugDiscoverRunner__init__.py 传递给 super().__init__(debug_sql=True, verbosity=2) 的参数没有了 *args, **kwargs

,为什么呢?

因为会报错!!!

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bash复制代码vagrant@vagrant:/vagrant$ python manage.py test comments
Traceback (most recent call last):
File "manage.py", line 22, in <module>
main()
File "manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.6/dist-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.6/dist-packages/django/core/management/__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.6/dist-packages/django/core/management/commands/test.py", line 23, in run_from_argv
super().run_from_argv(argv)
File "/usr/local/lib/python3.6/dist-packages/django/core/management/base.py", line 330, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.6/dist-packages/django/core/management/base.py", line 371, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.6/dist-packages/django/core/management/commands/test.py", line 52, in handle
test_runner = TestRunner(**options)
File "/vagrant/testing/testrunner.py", line 6, in __init__
super(DebugDiscoverRunner, self).__init__(debug_sql=True, verbosity=2, *args, **kwargs)
TypeError: __init__() got multiple values for keyword argument 'verbosity'

参考文章:Django:DiscoverRunner覆盖引发错误

参考归参考,但是这个人的处理方法很不好

所以我们去掉了 *args, **kwargs

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%