模拟Mysql Cursor类的fetchone()方法并将其返回值设置为None

4ioopgfo  于 2023-05-28  发布在  Mysql
关注(0)|答案(1)|浏览(183)

我试图创建mysql连接器的MagicMock示例,但我需要方法fetchone()返回None。
这是我到目前为止所做的:

with mock.patch('mysql.connector.cursor') as dbmock, \
       mock.patch('mysql.connector.connect', mock.MagicMock()):
        dbcursor_mock = dbmock.return_value  # Get the mock for the cursor
        dbcursor_mock.fetchone.return_value = None  # Set the return value of fetchone

问题是这返回一个MagicMock示例,而不是None
现在,如果我删除第二个patch(),它就可以工作了:

with mock.patch('mysql.connector.cursor') as dbmock):
        dbcursor_mock = dbmock.return_value  
        dbcursor_mock.fetchone.return_value = None  # this does return None, Why?

但是我的代码将尝试连接到数据库并失败。
我在上下文管理器中使用MySQL游标,如下所示:

def fetch_a_row():
# establishing the connection
with mysql.connector.connect(user='root',password='password',host='127.0.0.1',database='mydb') as conn:
    # Creating a cursor object using the cursor() method
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM mytable")
    # return the fetchone() output
    return cursor.fetchone()

我怎样才能让MagicMock的示例返回None?

ddarikpa

ddarikpa1#

使用patch.object()和side_effect

我写了一个测试,可以强制fetchone()返回None,通过使用:

  • 函数with mock.patch()来获取mock对象,它避免了与数据库的真实的连接(与代码中的完全一样)
  • 函数with mock.path.object()模拟方法cursor()
  • side_effect而不是return_value,以强制fetchone()返回None

适合您需要的测试应该如下:

import unittest
from unittest import mock

import mysql.connector

def fetch_a_row():
    # establishing the connection
    conn = mysql.connector.connect(user='root',password='password',host='127.0.0.1',database='mydb')
    # Creating a cursor object using the cursor() method
    cursor = conn.cursor()
    # return the fetchone() output
    return cursor.fetchone()

class TestMysqlConn(unittest.TestCase):

    def test_01(self):
        # following patch() is the same you have used in your code
        with mock.patch('mysql.connector.connect') as mock_connect:
            mock_connect_instance = mock_connect.return_value
            # mock the method cursor() of the mock object mock_connect
            with mock.patch.object(mock_connect_instance, 'cursor') as mock_cursor:
                mock_cursor_instance = mock_cursor.return_value
                # force fetchone() to return None by side_effect
                mock_cursor_instance.fetchone.side_effect = [None]
                # check if fetch_a_row() return None
                self.assertEqual(None, fetch_a_row())

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

在代码中,我编写了函数fetch_one_row(),它模拟了你的产品代码。

EDIT:我已经编辑了答案,因为OP添加了他的函数fetch_a_row()的代码。

使用上下文管理器测试

您已经编辑了您的问题,并使用上下文管理器添加了函数fetch_a_row()的代码。
当您使用上下文管理器时,调用方法__enter__()(参见this link),此方法返回对象conn。因此,使用上下文管理器,我必须修改测试函数如下:

import unittest
from unittest import mock

import mysql.connector

def fetch_a_row():
    # establishing the connection
    with mysql.connector.connect(user='root',password='password',host='127.0.0.1',database='mydb') as conn:
        # Creating a cursor object using the cursor() method
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM mytable")
        # return the fetchone() output
        return cursor.fetchone()

class TestMysqlConn(unittest.TestCase):

    def test_01(self):
        with mock.patch('mysql.connector.connect') as mock_connect:
            mock_connect_instance = mock_connect.return_value
            with mock.patch.object(mock_connect_instance, '__enter__') as mock_connect_context_manager:
                mock_connect_context_manager_instance = mock_connect_context_manager.return_value
                with mock.patch.object(mock_connect_context_manager_instance, 'cursor') as mock_cursor:
                    mock_cursor_instance = mock_cursor.return_value
                    mock_cursor_instance.fetchone.side_effect = [None]
                    self.assertEqual(None, fetch_a_row())

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

相关问题