Мокирование тестов pytest с помощью декоратора @patch из модуля unittest.mock

Вопросы и ответы

Проблема с мокированием send_request() в юнит-тестах

У меня возникли проблемы с мокированием функции send_request() в моих тестах. Несмотря на использование patch, оригинальная функция send_request() вызывается, и мок не применяется. Вот соответствующий вывод и код:

Вывод:

Send_click
send_request mock: <function send_request at 0x7f9c2146de40>
send request

Код:

logic.py

def send_request(manager, action_method, url, data=None, params=None, headers=None):
    print("send request")

test_ui.py

from ..ui import UserInterface
from unittest.mock import patch, Mock

@patch("ui.send_request")
def test_send_request(mock_send_request, qtbot):
    ui = UserInterface()
    ui.get_request_data = Mock()
    data = QByteArray(data_str_create.encode("utf-8"))
    action_method, url, data = ACTIONS_METHODS.POST, QUrl("http://example.com/api"), data
    ui.get_request_data.return_value = action_method, url, data
    ui.send_click()
    mock_send_request.assert_called_once()

Проблема:

  • send_request() не замокирован; оригинальная функция выполняется. Это подтверждается появлением send request в выводе и типом function в выводе.
  • AssertionError в последней строке теста указывает на то, что мок не был применён.

Как используется send_request():

ui.py

from logic import handle_response, send_request

class UserInterface(QWidget):
    # другие методы

    def get_request_data(self):
        action_method = self.combo_box.currentText()
        json_dict = json.loads(
            self.body.toPlainText().encode("utf-8").decode("unicode_escape")
        )
        json_data = json.dumps(json_dict).encode("utf-8")
        data = QByteArray(json_data)
        url = QUrl(self.url.text())
        return action_method, url, data

    def send_click(self):
        print("Send_click")
        print(f"send_request mock: {send_request}")
        send_request(self.rest_manager, *self.get_request_data())

Может кто-нибудь помочь разобраться, почему функция send_request() не мокируется как ожидалось?

Ответ

Проблема, с которой вы столкнулись, связана с неверной путевой иерархией при использовании декоратора @patch для замены функции send_request(). Чтобы корректно замокировать функцию, вам нужно убедиться, что вы указываете правильный путь к функции, которую вы хотите замокировать, относительно того, как она импортируется в вашем коде.

Причина проблемы

Вы используете @patch("ui.send_request"), чтобы замокировать send_request, но функция на самом деле импортируется из модуля logic. Когда вы вызываете send_request внутри класса UserInterface, Python ищет её именно в том модуле, из которого она была импортирована, а не в ui. Поэтому оригинальная функция вызывается вместо замокированной.

Решение

Чтобы исправить эту проблему, вам нужно изменить путь, который вы указываете для замокирования, на путь, соответствующий модулю logic, откуда импортируется send_request. Попробуйте заменить строку декоратора на:

@patch("logic.send_request")

Обновленный код теста

Вот как должен выглядеть ваш тестовый метод с исправлениями:

from ..ui import UserInterface
from unittest.mock import patch, Mock
from logic import ACTIONS_METHODS
from PyQt5.QtCore import QByteArray
from PyQt5.QtCore import QUrl

@patch("logic.send_request")  # Изменен путь для правильного замокирования
def test_send_request(mock_send_request, qtbot):
    ui = UserInterface()
    ui.get_request_data = Mock()

    data_str_create = '{"key": "value"}'  # добавлено для примера
    data = QByteArray(data_str_create.encode("utf-8"))
    action_method, url = ACTIONS_METHODS.POST, QUrl("http://example.com/api")

    # Возвращаем действие и URL до того, как будет вызвана send_click
    ui.get_request_data.return_value = action_method, url, data

    ui.send_click()

    mock_send_request.assert_called_once()  # Проверяем, был ли вызван замокированный метод

Дополнительные рекомендации:

  1. Проверьте структуру импортов: Убедитесь, что send_request импортируется в ui.py именно из logic, и проверьте, что остальная часть кода не создает конфликтов с именами.

  2. Логирование: Используйте print() для отладки, чтобы убедиться, что Mock работает, до того, как дошли до вызова send_click.

  3. Отключение других декораторов: Если в вашем проекте используются другие декораторы или фреймворки, это может повлиять на поведение теста. Убедитесь, что вы не вызываете другие модули, влияющие на замокированные функции.

Следуя этим шагам, вы должны успешно замокировать функцию send_request и избежать вызова оригинальной версии в ваших тестах.

Оцените материал
Добавить комментарий

Капча загружается...