Мок-объекты используются для имитации ошибок и исключений, перехватывая вызовы зависимостей и заменяя их контролируемым поведением. Например:
  
   from unittest.mock import patch, Mock
   import pytest
   def function_to_test(api_client):
       try:
           data = api_client.fetch_data()
           return process_data(data)
       except APIError as e:
           return f"Error: {e}"
   class APIError(Exception):
       pass
   def test_function_with_api_error():
       mock_api_client = Mock()
       mock_api_client.fetch_data.side_effect = APIError("Simulated API Error")
       result = function_to_test(mock_api_client)
       assert result == "Error: Simulated API Error"
  
  
  Здесь side_effect позволяет моку бросать исключение, имитируя сбой API.  pytest (или unittest) используются для организации и запуска теста, а assert подтверждает ожидаемое поведение.
Мок-объекты позволяют имитировать ошибки и исключения в тестах, чтобы проверить, как ваш код обрабатывает эти нештатные ситуации. Это критически важно для обеспечения надежности и отказоустойчивости. Вот несколько способов, как это сделать:
    1. Использование side_effect:
  
    Свойство side_effect мок-объекта может быть установлено в исключение, которое будет вызвано при каждом вызове мока.
  
import unittest
from unittest.mock import Mock
class MyClass:
    def my_method(self, value):
        # Предположим, что этот метод взаимодействует с внешним сервисом
        pass
class TestMyClass(unittest.TestCase):
    def test_my_method_raises_exception(self):
        # Создаем мок для метода, который мы хотим проверить на обработку исключений
        mock_method = Mock(side_effect=ValueError("Simulated error"))
        # Создаем экземпляр класса, содержащего метод, который мы мокаем
        instance = MyClass()
        instance.my_method = mock_method
        # Проверяем, что при вызове метода с моком возникает ожидаемое исключение
        with self.assertRaises(ValueError) as context:
            instance.my_method(10)
        self.assertEqual(str(context.exception), "Simulated error")
  
    В этом примере side_effect устанавливается равным ValueError("Simulated error").  Когда instance.my_method(10) вызывается, вместо реального выполнения метода выбрасывается исключение ValueError. assertRaises проверяет, что именно это исключение и было выброшено, и что его сообщение соответствует ожидаемому.
  
    2. Использование return_value и условной логики в side_effect:
  
    Можно использовать side_effect с функцией, которая решает, возвращать ли значение или вызывать исключение, основываясь на аргументах вызова.
  
import unittest
from unittest.mock import Mock
class MyClass:
    def my_method(self, value):
        # Предположим, что этот метод взаимодействует с внешним сервисом
        pass
class TestMyClass(unittest.TestCase):
    def test_my_method_conditional_exception(self):
        def side_effect_func(value):
            if value < 0:
                raise ValueError("Value cannot be negative")
            return value * 2
        mock_method = Mock(side_effect=side_effect_func)
        instance = MyClass()
        instance.my_method = mock_method
        # Проверяем исключение при отрицательном значении
        with self.assertRaises(ValueError) as context:
            instance.my_method(-5)
        self.assertEqual(str(context.exception), "Value cannot be negative")
        # Проверяем нормальное выполнение при положительном значении
        result = instance.my_method(5)
        self.assertEqual(result, 10)
  
    Здесь side_effect - это функция side_effect_func, которая принимает аргумент value. Если value отрицательное, она выбрасывает ValueError. В противном случае она возвращает value * 2. Это позволяет имитировать различные сценарии ошибок в зависимости от входных данных.
  
3. Мокирование контекстных менеджеров, вызывающих исключения:
Можно мокировать контекстные менеджеры, чтобы они вызывали исключения при входе или выходе. Это полезно для тестирования операций, связанных с файлами или сетевыми соединениями.
import unittest
from unittest.mock import Mock, patch
class MyClass:
    def read_file(self, filename):
        with open(filename, 'r') as f:
            return f.read()
class TestMyClass(unittest.TestCase):
    @patch('__main__.open')  # Обратите внимание: мокируем встроенную функцию open
    def test_read_file_raises_exception(self, mock_open):
        mock_file = Mock()
        mock_file.read.side_effect = IOError("File not found")  # Имитируем ошибку чтения файла
        mock_open.return_value = mock_file  # open() возвращает мок-объект, который имитирует файл
        instance = MyClass()
        with self.assertRaises(IOError) as context:
            instance.read_file("nonexistent_file.txt")
        self.assertEqual(str(context.exception), "File not found")
  
    В этом примере мы мокируем встроенную функцию open.  mock_file.read.side_effect = IOError("File not found") заставляет метод read() мок-объекта "файла" выбрасывать исключение IOError. Затем мы проверяем, что при вызове instance.read_file("nonexistent_file.txt") выбрасывается ожидаемое исключение.
  
Важные замечания:
assertRaises: Для проверки исключений используйте self.assertRaises(ExceptionType) в unittest.