unittest.mock. 
  MagicMock:  Подходит для большинства случаев.  Можно настроить возвращаемые значения и побочные эффекты (side_effect) для разных вызовов методов.Mock: Более простой, но менее мощный, чем MagicMock.patch: Для замены реальных объектов моками в тестах.  Используйте его для подмены объектов с большим количеством методов.Mock или MagicMock, и переопределите нужные методы, чтобы они возвращали желаемые значения или выполняли определенные действия. Это дает максимальный контроль.MagicMock):
  
   from unittest.mock import MagicMock
   # Создаем мок-объект
   mock_object = MagicMock()
   # Настраиваем возвращаемые значения для разных методов
   mock_object.method_one.return_value = 10
   mock_object.method_two.return_value = "hello"
   mock_object.method_three.side_effect = [1, 2, 3]  # Возвращает последовательно 1, 2, 3 при каждом вызове
   # Проверяем работу мок-объекта
   print(mock_object.method_one())  # Output: 10
   print(mock_object.method_two())  # Output: hello
   print(mock_object.method_three()) # Output: 1
   print(mock_object.method_three()) # Output: 2
  
    Создание сложных мок-объектов, имитирующих работу с несколькими методами, - важный навык при написании юнит-тестов.  В Python для этого часто используют библиотеку unittest.mock (или просто mock для старых версий Python).
  
    Основная идея заключается в создании экземпляра класса Mock и настройке атрибутов этого экземпляра таким образом, чтобы они представляли различные методы, возвращающие предопределенные значения или выполняющие определенные действия.
  
Вот несколько распространенных подходов:
return_value: Этот атрибут позволяет определить, что метод должен возвращать при каждом вызове.
      
from unittest.mock import Mock
# Создаем мок-объект
my_mock = Mock()
# Настраиваем return_value для метода 'method_a'
my_mock.method_a.return_value = 'Result from method_a'
# Настраиваем return_value для метода 'method_b'
my_mock.method_b.return_value = 42
# Теперь, когда мы вызываем эти методы, они возвращают заданные значения
print(my_mock.method_a())  # Output: Result from method_a
print(my_mock.method_b())  # Output: 42
      side_effect: Этот атрибут позволяет определить функцию, которая будет вызываться при каждом вызове метода. Функция может возвращать значение, выбросить исключение или выполнять другие действия.
      
from unittest.mock import Mock
def side_effect_function(arg1, arg2):
  if arg1 > 10:
    return arg1 * arg2
  else:
    raise ValueError("arg1 must be greater than 10")
my_mock = Mock()
my_mock.method_c.side_effect = side_effect_function
# Вызов с валидными аргументами
print(my_mock.method_c(15, 2))  # Output: 30
# Вызов с невалидными аргументами
try:
  my_mock.method_c(5, 2)
except ValueError as e:
  print(e)  # Output: arg1 must be greater than 10
      Mock: Можно создавать вложенные мок-объекты и определять цепочки вызовов.
      
from unittest.mock import Mock
# Создаем мок-объект для внутреннего компонента
inner_mock = Mock()
inner_mock.calculate.return_value = 100
# Создаем основной мок-объект
outer_mock = Mock()
outer_mock.inner_component = inner_mock
# Функция, использующая inner_component
def my_function(obj):
  return obj.inner_component.calculate() + 50
# Проверяем, что функция правильно использует мок-объект
result = my_function(outer_mock)
print(result)  # Output: 150
inner_mock.calculate.assert_called_once()
      PropertyMock: Для мокирования свойств объекта, особенно когда нельзя напрямую присвоить значение.
        
from unittest.mock import Mock, PropertyMock
class MyClass:
    @property
    def my_property(self):
        # Some complex calculation
        return 10
my_object = MyClass()
# Мокируем свойство my_property
with patch('__main__.MyClass.my_property', new_callable=PropertyMock) as mock_my_property:
    mock_my_property.return_value = 20
    print(my_object.my_property) # Output: 20
        Важно:
assert_called_once(), assert_called_with() и другие методы mock для проверки, что методы были вызваны с ожидаемыми аргументами.
    call_args_list для анализа истории вызовов.
    При проектировании тестов, стремитесь к тому, чтобы мок-объекты были максимально простыми и отражали только то поведение, которое необходимо для тестирования конкретного участка кода. Избегайте создания слишком сложных моков, которые могут сделать тесты хрупкими и сложными для понимания. Лучше разбить сложный тест на несколько более простых, каждый из которых проверяет определенный аспект поведения.