preface

Do it yourself

Before in the sifu raised this question, but no one answered ah, that can only solve their own!

How does Django print SQL statements even when unit testing

Not only think no, stackOverflow but no one answered

How do I output SQL statements

Add the following to your project’s settings.py file to translate all database operations into SQL statements, but note that this mode only works if the DEBUG in settings.py is True!

LOGGING = {
    'version': 1.'disable_existing_loggers': False.'handlers': {
        'console': {'level':'DEBUG'.'class':'logging.StreamHandler',}},'loggers': {
        'django.db.backends': {
            'handlers': ['console'].'propagate': True.'level':'DEBUG',}}}Copy the code

Output requirements for SQL statements in unit tests

The above statement does not work well when doing unit tests!

No SQL statement output at all!!

At first, I thought the level setting in the above code was wrong, and I should change DEBUG to production. Of course, the answer is not so!

To find the answer

Why is there a need? In fact, it is for the convenience of debugging code, but since it is debugging code, if the operation of the database does not output SQL statements, it feels like a fog, black box operation makes people feel confused!! How can a good programmer allow this to happen? Of course not!!

So I went through the official Django documentation

  • Write and run tests

    From reading the documentation, you can see that unit tests are run in production mode, which explains why SQL statements are not output because our log level is set to DEBUG

    Regardless of the DEBUG setting in the configuration file, all Django tests are run with DEBUG=False. This is to ensure that the output observed by your code is consistent with the output in production.

  • Log management Quick Start

    Ok, the direction of improvement has been found, so level should be changed to production mode.

    But after reading the document, I found only:

    • DEBUG: Indicates low-level system information used for troubleshooting
    • INFO: Indicates general system information
    • WARNING: Describes minor problems that occur in the system
    • ERROR: Indicates that a major system problem occurs
    • CRITICAL: Indicates the information about a serious system problem

    Of these five modes, the lowest is DEBUG, there is no production mode at all!!

  • Define the test runner

    After reading this document, I understand that the previous idea to modify level is wrong, we can and should customize the tester to make the unit test output SQL statements!!

Just do it!

To start

Create a new Testing folder under the root directory, then create a testcases.py file in it and write the following code:

from django.test.runner import DiscoverRunner


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

Copy the code

This code has several key points

  • Inheritance DiscoverRunner

    There’s nothing to say about that, the default is DiscoverRunner, so we inherit it, right

  • debug_sql=True, verbosity=2

    Inherit it for nothing, just like turning on the two arguments above

The names of testing and testcases.py are optional, but I am used to placing and naming them this way, you are optional!!

Then add the following code anywhere in settings.py:

TEST_RUNNER = 'testing.testrunner.DebugDiscoverRunner'
Copy the code

At this point, all you need is terminal input

python manage.py test
Copy the code

We will call our DebugDiscoverRunner to do unit test, execute __init__.py to pass debug_SQL =True, verbosity=2, and then the console will print SQL statements continuously!!

Some of the details

You will notice that the __init__.py of the DebugDiscoverRunner passed to super().__init__(debug_SQL =True, Verbosity =2) arguments are missing *args, **kwargs

Why?

Because of the error!!

As follows:

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/set p y", line 401, in execute_from_command_line
    utility.execute()
  File "/ usr/local/lib/python3.6 / dist - packages/django/core/management/set p y", 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. The p y", 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. The p y", 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'

Copy the code

Reference article: Django: DiscoverRunner override throws errors

Reference to reference, but this person’s handling is not good

So we got rid of *args, **kwargs