I will expand @G_M answer with example since I have two objections:
- In my opinion, it is a good practice to explicitly close database cursor, more about this here: Necessity of explicit cursor.close(). This can be done by using the cursor as a context manager, more in Django docs: https://docs.djangoproject.com/en/dev/topics/db/sql/#connections-and-cursors.
- When using
mock
we should not patch objects where they are defined:
The basic principle is that you patch where an object is looked up,
which is not necessarily the same place as where it is defined. A
couple of examples will help to clarify this.
Ref: https://docs.python.org/3/library/unittest.mock.html#where-to-patch
Example:
Our function we want to test:
# foooo_bar.py
from typing import Optional
from django.db import DEFAULT_DB_ALIAS, connections
def some_function(some_arg: str, db_alias: Optional[str] = DEFAULT_DB_ALIAS):
with connections[db_alias].cursor() as cursor:
cursor.execute('SOME SQL FROM %s;', [some_arg])
Test:
# test_foooo_bar.py
from unittest import mock
from django.db import DEFAULT_DB_ALIAS
from django.test import SimpleTestCase
from core.db_utils.xx import some_function
class ExampleSimpleTestCase(SimpleTestCase):
@mock.patch('foooo_bar.connections')
def test_some_function_executes_some_sql(self, mock_connections):
mock_cursor = mock_connections.__getitem__(DEFAULT_DB_ALIAS).cursor.return_value.__enter__.return_value
some_function('fooo')
# Demonstrating assert_* options:
mock_cursor.execute.assert_called_once()
mock_cursor.execute.assert_called()
mock_cursor.execute.assert_called_once_with('SOME SQL FROM %s;', ['fooo'])