UnitTest.Mock-如何从连接对象嘲笑对Cursor.execute()的调用



我试图用以下代码将Cursor.execute((用模拟固定,以使我可以测试execute均使用正确格式的查询来调用:

// Module ABC
def buildAndExecuteQuery( tablesAndColumnsToSelect ):
   '''Build and execute a query.
   Args: tablesAndColumnsToSelect (dict)
         - keys are table names, values are columns
   '''
   query = ..... < logic to build query > ....
   from django.db import connections
   cursor = connections[ 'mydb' ].cursor()
   cursor.execute( query )

如何使用模拟库在Python2.7中完成此类模拟?

我将扩展@g_m答案,因为我有两个反对意见:

  1. 在我看来,要明确关闭数据库光标是一种很好的做法,在此处进行更多有关:显式光标的必要性((。这可以通过将光标用作上下文管理器来完成,更多在Django文档中:https://docs.djangoproject.com/en/dev/topics/db/db/sql/sql/#connections-and-cursors.
  2. 使用mock时,我们不应在定义的位置进行修补对象:

基本原理是您在查找对象的地方进行修补, 这不一定与定义的位置相同。A 几个示例将有助于澄清这一点。

参考:https://docs.python.org/3/library/unittest.mock.html#where-where-to-patch

示例:

我们要测试的功能:

# 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_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'])

由于我不知道您的查询逻辑是什么,所以我修改了query只是通过tables_and_columns_to_select参数直接接受前哨值。

# b_and_ex_q.py

def build_and_execute_query(tables_and_columns_to_select):
    """Build and execute a query.
    Args: tablesAndColumnsToSelect (dict)
          - keys are table names, values are columns
    """
    query = tables_and_columns_to_select  # ..... < logic to build query > ....
    from django.db import connections
    cursor = connections['mydb'].cursor()
    cursor.execute(query)

import unittest
from mock import patch, sentinel
from b_and_ex_q import build_and_execute_query

class TestCursorExecute(unittest.TestCase):
    @patch('django.db.connections')
    def test_build_and_execute_query(self, mock_connections):
        # Arrange
        mock_cursor = mock_connections.__getitem__('mydb').cursor.return_value
        # Act
        build_and_execute_query(sentinel.t_and_c)
        # Assert
        mock_cursor.execute.assert_called_once_with(sentinel.t_and_c)

if __name__ == '__main__':
    unittest.main()

相关内容

  • 没有找到相关文章

最新更新